bitkeeper revision 1.712 (40278da0FlDvMYRMecrIx93_mifB0Q)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 9 Feb 2004 13:39:44 +0000 (13:39 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 9 Feb 2004 13:39:44 +0000 (13:39 +0000)
xc_netbsd_build.c, xc_elf.h, xendomains, netbsd:
  new file
Many files:
  Pull in user-space updates from v1.2.

14 files changed:
.rootkeys
docs/VBD-HOWTO.txt
tools/examples/Makefile
tools/examples/README
tools/examples/defaults
tools/examples/democd
tools/examples/netbsd [new file with mode: 0644]
tools/examples/xc_dom_control.py
tools/examples/xc_dom_create.py
tools/examples/xendomains [new file with mode: 0755]
tools/xc/lib/xc.h
tools/xc/lib/xc_elf.h [new file with mode: 0644]
tools/xc/lib/xc_netbsd_build.c [new file with mode: 0644]
tools/xc/py/Xc.c

index 39b21219d8b23c4aa06e24691068066f19c3a5f7..a487b18871e67e4779d25fbbf28b6b5782879003 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 401d7e16UgeqroJQTIhwkrDVkoWgZQ tools/examples/README
 401d7e16GS8YesM1zateRbaOoI6YLQ tools/examples/defaults
 401d7e16NoWaBGC1RXbBcqAOr5Uaag tools/examples/democd
+40278d91ZjLhxdjjrGe8HEdwHLj5xQ tools/examples/netbsd
 401d7e16NpnVrFSsR7lKKKfTwCYvWA tools/examples/xc_dom_control.py
 401d7e16RJj-lbtsVEjua6HYAIiKiA tools/examples/xc_dom_create.py
 401d7e16X4iojyKopo_j63AyzYZd2A tools/examples/xc_vd_tool.py
+40278d94cIUWl2eRgnwZtr4hTyWT1Q tools/examples/xendomains
 3f776bd2Xd-dUcPKlPN2vG89VGtfvQ tools/misc/Makefile
 3f6dc136ZKOjd8PIqLbFBl_v-rnkGg tools/misc/miniterm/Makefile
 3f6dc140C8tAeBfroAF24VrmCS4v_w tools/misc/miniterm/README
 3fbba6dcrNxtygEcgJYAJJ1gCQqfsA tools/xc/lib/xc.h
 3fbba6dbEVkVMX0JuDFzap9jeaucGA tools/xc/lib/xc_bvtsched.c
 3fbba6dbasJQV-MVElDC0DGSHMiL5w tools/xc/lib/xc_domain.c
+40278d99BLsfUv3qxv0I8C1sClZ0ow tools/xc/lib/xc_elf.h
 3fbba6dbNCU7U6nsMYiXzKkp3ztaJg tools/xc/lib/xc_linux_build.c
 3fbba6dbl267zZOAVHYLOdLCdhcZMw tools/xc/lib/xc_linux_restore.c
 3fbba6db7li3FJiABYtCmuGxOJxEGw tools/xc/lib/xc_linux_save.c
 3fbba6db7WnnJr0KFrIFrqNlSKvFYg tools/xc/lib/xc_misc.c
+40278d9ctaHVDaEuwhXI3Om2JOjx9w tools/xc/lib/xc_netbsd_build.c
 3fbba6dctWRWlFJkYb6hdix2X4WMuw tools/xc/lib/xc_private.c
 3fbba6dcbVrG2hPzEzwdeV_UC8kydQ tools/xc/lib/xc_private.h
 3fbba6dcoGq9hQlksrBUfC2P5F6sGg tools/xc/lib/xc_vbd.c
index 9abec5d482838428f3d6f50be89ffef3aa6f9c4f..b1a4f2dd3f80e31a1fa56fe7fd7fea0546d8a866 100644 (file)
@@ -21,10 +21,13 @@ Virtual Block Devices (VBDs):
 
        A virtual block device can also consist of multiple extents from the
        physical disks in the system, allowing them to be accessed as a single
-       uniform device from the domain with access to that VBD.
+       uniform device from the domain with access to that VBD.  The
+       functionality is somewhat similar to that underpinning LVM, since
+       you can combine multiple regions from physical devices into a single
+       logical device, from the point of view of a guest virtual machine.
 
-       Everyone who uses Xen / XenoLinux uses VBDs but for less advanced uses
-       they can almost be ignored.
+       Everyone who boots Xen / XenoLinux from a hard drive uses VBDs
+       but for some uses they can almost be ignored.
 
 Virtual Disks (VDs):
        VDs are an abstraction built on top of the functionality provided by
@@ -43,10 +46,12 @@ Virtual Disks (VDs):
        don't want to have to keep repartitioning in order to provide them with
        disk space.
 
+       Virtual Disks are rather like "logical volumes" in LVM.
+
 If that didn't all make sense, it doesn't matter too much ;-)  Using the
 functionality is fairly straightforward and some examples will clarify things.
 The text below expands a bit on the concepts involved, finishing up with a
-walkthrough of some simple virtual disk management tasks.
+walk-through of some simple virtual disk management tasks.
 
 
 Virtual Block Devices
@@ -58,39 +63,43 @@ functionality that will be useful to know.
 A VBD is made up of a number of extents from physical disk devices.  The
 extents for a VBD don't have to be contiguous, or even on the same device.  Xen
 performs address translation so that they appear as a single contiguous
-device.
+device to a domain.
 
 When the VBD layer is used to give access to entire drives or entire
-partitions, the VBDs simply consist of a single extent, corresponding to the
-drive or partition used.  When used with Virtual Disks, the extent list
-functionality will be used (discussed later).
+partitions, the VBDs simply consist of a single extent that corresponds to the
+drive or partition used.  Lists of extents are usually only used when virtual
+disks (VDs) are being used.
 
 Xen 1.2 and its associated XenoLinux release support automatic registration /
 removal of VBDs.  It has always been possible to add a VBD to a running
-XenoLinux domain but it was then necessary to run "xen_vbd_refresh" in order
-for the new device to be detected.  Nowadays, when a VBD is added, the domain
-it's added to automatically registers the disk.
+XenoLinux domain but it was then necessary to run the "xen_vbd_refresh" tool in
+order for the new device to be detected.  Nowadays, when a VBD is added, the
+domain it's added to automatically registers the disk, with no special action
+by the user being required.
 
 Note that it is possible to use the VBD functionality to allow multiple domains
 write access to the same areas of disk.  This is almost always a bad thing!
-
-The provided example script createlinuxdom.py does its best to check that disk
-areas are not shared unsafely and will catch many cases of this.  Setting the
-vbd_expert variable in that script controls how unsafe it allows VBD mappings
-to be - 0 should be right for most people ;-)
+The provided example scripts for creating domains do their best to check that
+disk areas are not shared unsafely and will catch many cases of this.  Setting
+the vbd_expert variable in config files for xc_dom_create.py controls how
+unsafe it allows VBD mappings to be - 0 (read only sharing allowed) should be
+right for most people ;-).  Level 1 attempts to allow at most one writer to any
+area of disk.  Level 2 allows multiple writers (i.e. anything!).
 
 
 Virtual Disk Management
 -----------------------
 
-The VD management code runs entirely in userspace.  The code is written in
+The VD management code runs entirely in user space.  The code is written in
 Python and can therefore be accessed from custom scripts, as well as from the
 convenience scripts provided.  The underlying VD database is a SQLite database
 in /var/db/xen_vdisks.sqlite.
 
-The scripts provided are as follows:
+Most virtual disk management can be performed using the xc_vd_tool.py script
+provided in the tools/examples/ directory of the source tree.  It supports the
+following operations:
 
-vd_format.py -      "Formats" a partition or disk device for use storing
+initialise -        "Formats" a partition or disk device for use storing
                     virtual disks.  This does not actually write data to the
                     specified device.  Rather, it adds the device to the VD
                     free-space pool, for later allocation.
@@ -100,7 +109,7 @@ vd_format.py -           "Formats" a partition or disk device for use storing
                     have created yourself as part of the free space pool has
                     undefined (possibly nasty) results.
 
-vd_create.py -      Creates a virtual disk of specified size by allocating space
+create -            Creates a virtual disk of specified size by allocating space
                     from the free space pool.  The virtual disk is identified
                     in future by the unique ID returned by this script.
 
@@ -108,14 +117,39 @@ vd_create.py -         Creates a virtual disk of specified size by allocating space
                     most users, the best idea is to specify a time of 0 (which
                     has the special meaning "never expire") and then
                     explicitly delete the VD when finished with it -
-                    otherwise, VDs could disappear unexpectedly...
+                    otherwise, VDs will disappear if allowed to expire.
+
+delete -            Explicitly delete a VD.  Makes it disappear immediately!
+
+setexpiry -         Allows the expiry time of a (not yet expired) virtual disk
+                    to be modified.  Be aware the VD will disappear when the
+                    time has expired.
+
+enlarge -            Increase the allocation of space to a virtual disk.
+                    Currently this will not be immediately visible to running
+                    domain(s) using it.  You can make it visible by destroying
+                    the corresponding VBDs and then using xc_dom_control.py to
+                    add them to the domain again.  Note: doing this to
+                    filesystems that are in use may well cause errors in the
+                    guest Linux, or even a crash although it will probably be
+                    OK if you stop the domain before updating the VBD and
+                    restart afterwards.
 
-vd_refresh.py -             Allows the expiry time of a (not yet expired) virtual disk to
-                    be modified.  Be aware the VD will disappear when the time has
-                    expired.
+import -            Allocate a virtual disk and populate it with the contents of
+                    some disk file.  This can be used to import root file system
+                    images or to restore backups of virtual disks, for instance.
 
-vd_delete.py -      Explicitly delete a VD.  Makes it disappear immediately.
+export -            Write the contents of a virtual disk out to a disk file.
+                    Useful for creating disk images for use elsewhere, such as
+                    standard root file systems and backups.
 
+list -              List the non-expired virtual disks currently available in the
+                    system.
+
+undelete -          Attempts to recover an expired (or deleted) virtual disk.
+
+freespace -         Get the free space (in megabytes) available for allocating
+                    new virtual disk extents.
 
 The functionality provided by these scripts is also available directly from
 Python functions in the XenoUtil module - you can use this functionality in
@@ -124,31 +158,40 @@ your own scripts.
 Populating VDs:
 
 Once you've created a VD, you might want to populate it from DOM0 (for
-instance, to put a root filesystem onto it for a guest domain).  This can be
-done by dynamically creating a VBD - this is discussed below.
+instance, to put a root file system onto it for a guest domain).  This can be
+done by creating a VBD for dom0 to access the VD through - this is discussed
+below.
 
-More detail:
+More detail on how virtual disks work:
 
-When you use vd_format.py to add a device to the free space pool, the device is
-logically split up into extents.  These extents are recorded in the Virtual
-Disk Management database in /var/db/xen_vdisks.sqlite.
+When you "format" a device for virtual disks, the device is logically split up
+into extents.  These extents are recorded in the Virtual Disk Management
+database in /var/db/xen_vdisks.sqlite.
 
-When you use vd_create.py to add create a virtual disk, some of the extents in
+When you use xc_vd_tool.py to add create a virtual disk, some of the extents in
 the free space pool are reallocated for that virtual disk and a record for that
 VD is added to the database.  When VDs are mapped into domains as VBDs, the
 system looks up the allocated extents for the virtual disk in order to set up
 the underlying VBD.
 
 Free space is identified by the fact that it belongs to an "expired" disk.
-When vd_format.py adds a real device to the free pool, it actually divides it
-into extents and adds them to an already-expired virtual disk.
+When "initialising" with xc_vd_tool.py adds a real device to the free pool, it
+actually divides the device into extents and adds them to an already-expired
+virtual disk.  The allocated device is not written to during this operation -
+its availability is simply recorded into the virtual disks database.
 
 If you set an expiry time on a VD, its extents will be liable to be reallocated
 to new VDs as soon as that expiry time runs out.  Therefore, be careful when
-setting expiry times.
+setting expiry times!  Many users will find it simplest to set all VDs to not
+expire automatically, then explicitly delete them later on.
 
-Finally, vd_delete.py can be used to delete virtual disks when they are no
-longer needed.  It works by causing them to expire immediately.
+Deleted / expired virtual disks may sometimes be undeleted - currently this
+only works when none of the virtual disk's extents have been reallocated to
+other virtual disks, since that's the only situation where the disk is likely
+to be fully intact.  You should try undeletion as soon as you realise you've
+mistakenly deleted (or allowed to expire) a virtual disk.  At some point in the
+future, an "unsafe" undelete which can recover what remains of partially
+reallocated virtual disks may also be implemented.
 
 Security note:
 
@@ -156,26 +199,33 @@ The disk space for VDs is not zeroed when it is initially added to the free
 space pool OR when a VD expires OR when a VD is created.  Therefore, if this is
 not done manually it is possible for a domain to read a VD to determine what
 was written by previous owners of its constituent extents.  If this is a
-problem, users should manually clean the VD in some way before allocating
+problem, users should manually clean VDs in some way either on allocation, or
+just before deallocation (automated support for this may be added at a later
+date).
 
 
 Dynamically Registering VBDs
 ----------------------------
 
-Two scripts are included to make it easy to add VDs to domains.
+The domain control tool (xc_dom_control.py) includes the ability to add and
+remove VBDs to / from running domains.  As usual, the command format is:
+
+xc_dom_control.py [operation] [arguments]
 
-add_vbd_to_dom.py -     Creates a VBD corresponding to either a physical
-                        device or a virtual disk and adds it as a specified
-                        device under the target domain, with either read or
-                        write access.
+The operations (and their arguments) are as follows:
 
-remove_vbd_from_dom.py - Removes the VBD associated with a specified device
-                        node from the target domain.
+vbd_add dom uname dev mode - Creates a VBD corresponding to either a physical
+                            device or a virtual disk and adds it as a
+                            specified device under the target domain, with
+                            either read or write access.
+
+vbd_remove dom dev        - Removes the VBD associated with a specified device
+                            node from the target domain.
 
 These scripts are most useful when populating VDs.  VDs can't be populated
 directly, since they don't correspond to real devices.  Using:
 
-  add_vbd_to_dom.py vd:your_vd_id /dev/wherever 0 rw
+  xc_dom_control.py vbd_add vd:your_vd_id /dev/whatever 0 w
 
 You can make a virtual disk available to DOM0.  Sensible devices to map VDs to
 in DOM0 are the /dev/xvd* nodes, since that makes it obvious that they are Xen
@@ -184,90 +234,184 @@ virtual devices that don't correspond to real physical devices.
 You can then format, mount and populate the VD through the nominated device
 node.  When you've finished, use:
 
-  remove_vbd_from_dom.py /dev/whatever 0
+  xc_dom_control.py vbd_remove /dev/whatever 0
 
 To revoke DOM0's access to it.  It's then ready for use in a guest domain.
 
 
 
-You can also use add_vbd_to_dom.py to grant access to a physical device to a
-guest - you might use this to temporarily share a partition, or to add access
-to a partition that wasn't granted at boot time.  Again, remove_vbd_from_dom.py
-allows you to revoke access.
+You can also use this functionality to grant access to a physical device to a
+guest domain - you might use this to temporarily share a partition, or to add
+access to a partition that wasn't granted at boot time.
 
 When playing with VBDs, remember that in general, it is only safe for two
-domains to have access to a filesystem if they both have read-only access.  You
-shouldn't be trying to share anything which is writeable, even if only by one
+domains to have access to a file system if they both have read-only access.  You
+shouldn't be trying to share anything which is writable, even if only by one
 domain, unless you're really sure you know what you're doing!
 
 
+Granting access to real disks and partitions
+--------------------------------------------
+
+During the boot process, Xen automatically creates a VBD for each physical disk
+and gives Dom0 read / write access to it.  This makes it look like Dom0 has
+normal access to the disks, just as if Xen wasn't being used - in reality, even
+Dom0 talks to disks through Xen VBDs.
+
+To give another domain access to a partition or whole disk then you need to
+create a corresponding VBD for that partition, for use by that domain.  As for
+virtual disks, you can grant access to a running domain, or specify that the
+domain should have access when it is first booted.
+
+To grant access to a physical partition or disk whilst a domain is running, use
+the xc_dom_control.py script - the usage is very similar to the case of adding
+access virtual disks to a running domain (described above).  Specify the device
+as "phy:device", where device is the name of the device as seen from domain 0,
+or from normal Linux without Xen.  For instance:
+
+> xc_dom_control.py vbd_add phy:hdc /dev/whatever 2 r
+
+Will grant domain 2 read-only access to the device /dev/hdc (as seen from Dom0
+/ normal Linux running on the same machine - i.e. the master drive on the
+secondary IDE chain), as /dev/whatever in the target domain.
+
+Note that you can use this within domain 0 to map disks / partitions to other
+device nodes within domain 0.  For instance, you could map /dev/hda to also be
+accessible through /dev/xvda.  This is not generally recommended, since if you
+(for instance) mount both device nodes read / write you could cause corruption
+to the underlying filesystem.  It's also quite confusing ;-)
+
+To grant a domain access to a partition or disk when it boots, the appropriate
+VBD needs to be created before the domain is started.  This can be done very
+easily using the tools provided.  To specify this to the xc_dom_create.py tool
+(either in a startup script or on the command line) use triples of the format:
+
+  phy:dev,target_dev,perms
+
+Where dev is the device name as seen from Dom0, target_dev is the device you
+want it to appear as in the target domain and perms is 'w' if you want to give
+write privileges, or 'r' otherwise.
+
+These may either be specified on the command line or in an initialisation
+script.  For instance, to grant the same access rights as described by the
+command example above, you would use the triple:
 
-Walkthrough: Booting a domain from a VD
----------------------------------------
+  phy:hdc,/dev/whatever,r
+
+If you are using a config file, then you should add this triple into the
+vbd_list variable, for instance using the line:
+
+  vbd_list = [ ('phy:dev', 'hdc', 'r') ]
+
+(Note that you need to use quotes here, since config files are really small
+Python scripts.)
+
+To specify the mapping on the commandline, you'd use the -d switch and supply
+the triple as the argument, e.g.:
+
+> xc_dom_create.py [other arguments] -d phy:hdc,/dev/whatever,r
+
+(You don't need to explicitly quote things in this case.)
+
+
+Walk-through: Booting a domain from a VD
+----------------------------------------
 
 As an example, here is a sequence of commands you might use to create a virtual
-disk, populate it with a root filesystem and boot a domain from it.  These
+disk, populate it with a root file system and boot a domain from it.  These
 steps assume that you've installed the example scripts somewhere on your PATH -
 if you haven't done that, you'll need to specify a fully qualified pathname in
-the examples below.  The steps also assume that you know how to use the
-createlinuxdom.py script provided and have already set it up for your local
-configuration, apart from the virtual disks info.
+the examples below.  It is also assumed that you know how to use the
+xc_dom_create.py tool (apart from configuring virtual disks!)
+
+[ This example is intended only for users of virtual disks (VDs).  You don't
+need to follow this example if you'll be booting a domain from a dedicated
+partition, since you can create that partition and populate it, directly from
+Dom0, as normal. ]
 
 First, if you haven't done so already, you'll initialise the free space pool by
 adding a real partition to it.  The details are stored in the database, so
 you'll only need to do it once.  You can also use this command to add further
 partitions to the existing free space pool.
 
-> vd_format.py /dev/<real partition>
+> xc_vd_tool.py format /dev/<real partition>
 
 Now you'll want to allocate the space for your virtual disk.  Do so using the
 following, specifying the size in megabytes.
 
-> vd_create.py <chosen size>
+> xc_vd_tool.py create <size in megabytes>
 
-At this point, the vd_create.py program will tell you the virtual disk ID.
-Note it down, as it is how you will identify the virtual device in future.
+At this point, the program will tell you the virtual disk ID.  Note it down, as
+it is how you will identify the virtual device in future.
 
 If you don't want the VD to be bootable (i.e. you're booting a domain from some
 other medium and just want it to be able to access this VD), you can simply add
-it to the vbds list in your custom createlinuxdom.py (step 5) and then run that
-script.  Any formatting / populating of the VD can be done from that domain.
+it to the vbd_list used by xc_dom_create.py, either by putting it in a config
+file or by specifying it on the command line.  Formatting / populating of the
+VD could then done from that domain once it's started.
 
 If you want to boot off your new VD as well then you need to populate it with a
 standard Linux root filesystem.  You'll need to temporarily add the VD to DOM0
 in order to do this.  To give DOM0 r/w access to the VD, use the following
 command line, substituting the ID you got earlier.
 
-> add_vbd_to_dom.py vd:<id> /dev/xvda 0 rw
+> xc_dom_control.py vbd_add vd:<id> /dev/xvda 0 w
 
-This attaches the VD to the device /dev/xvda - you can use other devices if you
-choose too but with the xvd* devices it's obvious you're using a virtual device.
+This attaches the VD to the device /dev/xvda in domain zero, with read / write
+privileges - you can use other devices nodes if you choose too.
 
 Now make a filesystem on this device, mount it and populate it with a root
 filesystem.  These steps are exactly the same as under normal Linux.  When
 you've finished, unmount the filesystem again.
 
 You should now remove the VD from DOM0.  This will prevent you accidentally
-changing it in DOM0, whilst the guest domain is using it.
+changing it in DOM0, whilst the guest domain is using it (which could cause
+filesystem corruption, and confuse Linux).
 
-> remove_vbd_from_dom.py /dev/xvda 0
+> xc_dom_control.py vbd_remove /dev/xvda 0
 
 It should now be possible to boot a guest domain from the VD.  To do this, you
-should add the VD's details to the vbds list in step 5 of createlinuxdom.py and
-set the value of rootbit in step 6.  For instance, you might add:
+should specify the the VD's details in some way so that xc_dom_create.py will
+be able to set up the corresponding VBD for the domain to access.  If you're
+using a config file, you should include:
 
-('vd:<id>', '/dev/xvda', 'w')
+  ('vd:<id>', '/dev/whatever', 'w')
 
-To the vbds list in step 5 - this gives the domain writeable access to the VD
-as if it were the domain's /dev/xvda.
+In the vbd_list, substituting the appropriate virtual disk ID, device node and
+read / write setting.
 
-Then you would set:
+To specify access on the command line, as you start the domain, you would use
+the -d switch (note that you don't need to use quote marks here):
 
-rootbit = "root=/dev/xvda ro"
+> xc_dom_create.py [other arguments] -d vd:<id>,/dev/whatever,w
 
-In step 6 to tell the kernel where the root filesystem is.
+To tell Linux which device to boot from, you should either include:
 
+  root=/dev/whatever
 
+in your cmdline_root in the config file, or specify it on the command line,
+using the -R option:
+
+> xc_dom_create.py [other arguments] -R root=/dev/whatever
+
+That should be it: sit back watch your domain boot off its virtual disk!
+
+
+Getting help
+------------
+
+The main source of help using Xen is the developer's e-mail list:
+<xen-devel@lists.sourceforge.net>.  The developers will help with problems,
+listen to feature requests and do bug fixes.  It is, however, helpful if you
+can look through the mailing list archives and HOWTOs provided to make sure
+your question is not answered there.  If you post to the list, please provide
+as much information as possible about your setup and your problem.
+
+There is also a general Xen FAQ, kindly started by Jan van Rensburg, which (at
+time of writing) is located at: <http://xen.epiuse.com/xen-faq.txt>.
+
+Contributing
+------------
 
-Once these variables are set, you can run createlinuxdom.py to start your new
-domain.
+Patches and extra documentation are also welcomed ;-) and should also be posted
+to the xen-devel e-mail list.
index 7a8089f74e594426930575cf87356567236e283c..a30340d70128e5433beb5b512bf0a2a5f3430b8e 100644 (file)
@@ -8,7 +8,8 @@ SRCS     = $(wildcard *.c)
 OBJS     = $(patsubst %.c,%.o,$(SRCS))
 
 INSTALL  = $(wildcard *.py)
-ETC     = defaults democd
+ETC     = defaults democd netbsd
+INITD    = xendomains
 
 all: 
 
@@ -17,14 +18,18 @@ install: all
        cp -a $(INSTALL) /usr/bin
        #chmod 755 $(INSTALL)
        mkdir -p /etc/xc
-       for i in $(ETC) ; do [ ! -e /etc/xc/$$i ] && echo Install $$i && cp $$i /etc/xc/ ; done || true 
+       for i in $(ETC) ; do [ ! -e /etc/xc/$$i ] && echo Install $$i && cp $$i /etc/xc/ ; done || true
+       mkdir -p /etc/xc/auto
+       for i in $(INITD) ; do [ -e /etc/init.d/ ] && [ ! -e /etc/init.d/$$i ] && cp $$i /etc/init.d/ ; done || true
 
 dist: all
        mkdir -p ../../../install/bin
        mkdir -p ../../../install/etc
+       mkdir -p ../../../install/init.d
        cp -a $(INSTALL) ../../../install/bin
        cp -a $(ETC) ../../../install/etc
        #chmod 755 $(INSTALL)
+       cp -a $(INITD) ../../../install/init.d
 
 clean:
 
index 13379bb5c46e836b0a6546e7618bd134cfd98f28..4d06bd9d62b8c099c468361bfa2789d82d0e2a9a 100644 (file)
@@ -18,10 +18,12 @@ xc_dom_control.py
   Usage: xc_dom_control.py [command] <params>
   stop      [dom]        -- pause a domain
   start     [dom]        -- un-pause a domain
-  shutdown  [dom]        -- request a domain to shutdown
+  shutdown  [dom]        -- request a domain to shutdown (can specify 'all')
+                            (optionally wait for complete shutdown)
   destroy   [dom]        -- immediately terminate a domain
   pincpu    [dom] [cpu]  -- pin a domain to the specified CPU
-  save      [dom] [file] -- suspend a domain's memory to file
+  suspend   [dom] [file] -- write domain's memory to a file and terminate
+                           (resume by re-running xc_dom_create with -L option)
   restore   [file]       -- resume a domain from a file
   list                   -- print info about all domains
   listvbds               -- print info about all virtual block devs
@@ -34,7 +36,7 @@ xc_dom_control.py
   vif_getsched [dom] [vif] -- print vif's scheduling parameters
   vbd_add [dom] [uname] [dev] [mode] -- make disk/partition uname available to 
                             domain as dev e.g. 'vbd_add phy:sda3 hda1 rw'
-  vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev' 
+  vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev'
 
 
 xc_dom_create.py
@@ -47,10 +49,12 @@ in [] brackets. Arguments are as follows:
 Arguments to control the parsing of the defaults file:
  -f config_file   -- Use the specified defaults script. 
                      Default: ['/etc/xc/defaults']
+ -L state_file    -- Load virtual machine memory state from state_file
  -D foo=bar       -- Set variable foo=bar before parsing config
-                     E.g. '-D vmid=3:ip=1.2.3.4'
+                     E.g. '-D vmid=3;ip=1.2.3.4'
  -h               -- Print extended help message, including all arguments
  -n               -- Dry run only, don't actually create domain
+ -q               -- Quiet - write output only to the system log
 
 
 The config file 'defaults' requires the following variable to be defined:
@@ -69,7 +73,7 @@ Arguments to override current config read from 'defaults':
  -d udisk,dev,rw  -- Add disk, partition, or virtual disk to domain. E.g. to 
                      make partion sda4 available to the domain as hda1 with 
                      read-write access: '-b phy:sda4,hda1,rw' To add 
-                     multiple disks use multiple -d flags or seperate with ':'
+                     multiple disks use multiple -d flags or seperate with ';'
                      Default: ['']
  -i vfr_ipaddr    -- Add IP address to the list which Xen will route to
                      the domain. Use multiple times to add more IP addrs.
@@ -107,3 +111,18 @@ xc_vd_tool
    device    - physical partition to 'format' to hold vd's. e.g. hda4
    ext_size  - extent size (default 64MB)
 
+
+xendomains
+This is a Sys-V init script for RedHat systems.
+
+ - Usage: xendomains {start|stop|status}
+
+   start  -- starts all the domains with config files in /etc/xc/auto/
+   stop   -- stops ALL running domains, waiting for them to shutdown cleanly
+             (if possible) before returning
+   status -- prints a list of the running domains, the same as
+             "xc_dom_control.py list"
+
+On a RedHat system it should be possible to issue commands to this
+script using the "service" command and to configure if / when it is
+run automatically, using the "chkconfig" command.
index 0afdebb7af81f78afc8e31890d8c2984a8c9032a..8852094eeadb17f0f81d14fc3da74f3987689131 100644 (file)
@@ -26,7 +26,7 @@ if vmid == 0:
 image = "../../../install/boot/xenolinux.gz"
 ramdisk = ""
 #ramdisk = "/boot/initrd.gz"
-builder_fn='xc.linux_build' # this is a linux domain
+builder_fn='linux' # this is a linux domain
 
 # STEP 2. The initial memory allocation (in megabytes) for the new domain.
 mem_size = 64
index da266f35ea5dce87db4c637b349facedef6568c8..4d6e90033f25b776ffe7698aea72dd24159d24ed 100644 (file)
@@ -8,7 +8,7 @@ def config_usage ():
     print >>sys.stderr, """
 The config file %s requires the following vars to be defined:
  ip               -- List of IP addr(s) for Xen to route to domain 
-                     e.g. -Dip='1.2.3.4,5.6.7.8'
+                     e.g. '-Dip=1.2.3.4,5.6.7.8'
 The following variables may be optionally defined:
  mem              -- Adjust initial memory allocation (default 64MB)
  netmask          -- Override gateway for kernel ip= command line
@@ -18,13 +18,13 @@ The following variables may be optionally defined:
 try:
     ip
 except:
-    print "Set variable 'ip' using -Dip='1.2.3.4,5.6.7.8'"
+    print "Set variable 'ip' using '-Dip=1.2.3.4,5.6.7.8'"
     assert()
 
 # STEP 1. Specify kernel image file and otional ramdisk. Can be gzip'ed.
 image   = "/boot/xenolinux.gz"
 ramdisk = "/boot/initrd.gz"
-builder_fn='xc.linux_build' # this is a linux domain
+builder_fn='linux' # this is a linux domain
 
 # STEP 2. The initial memory allocation (in megabytes) for the new domain.
 try:
@@ -34,7 +34,13 @@ except NameError:
 
 
 # STEP 3. A handy name for your new domain.
-domain_name = "Demo CD VM %s" % ip
+# appends either first hostname or last quad of first IP address dependant on value passed
+
+quads = string.split(ip, '.')
+if len(quads) == 4:                                    # fragile heuristic for valid IP verification
+       domain_name = "Xen VM .%s" % quads[3]           # use last quad of IP
+else:
+       domain_name = "Xen VM: %s" % ip                 # use hostname passed in
 
 
 # STEP 4. Specify IP address(es), for the new domain.  You need to
@@ -47,6 +53,7 @@ domain_name = "Demo CD VM %s" % ip
 vfr_ipaddr  = map(socket.gethostbyname,string.split(ip,','))
 
 
+
 # STEP 5a. Identify any physcial partitions or virtual disks you want the
 # domain to have access to, and what you want them accessible as
 # e.g. vbd_list = [ ('phy:sda1','sda1', 'w'),
@@ -72,46 +79,58 @@ vbd_expert = 0
 # You can use 'extrabit' to set the runlevel and custom environment
 # variables used by custom rc scripts (e.g. VMID=, usr= )
 
-try: 
-    netmask = socket.gethostbyname( netmask )
-except NameError:
-    netmask = XenoUtil.get_current_ipmask()
+
+# see if we have a local IP at all
+localip=''
+for i in vfr_ipaddr:
+    if XenoUtil.check_subnet(i,'169.254.0.0','255.255.0.0'):
+       localip=i
+       break
+
+
+# if either netmask and gateway has been set from the command line,
+# associate it with the first IP address that has been specified.
+
+myip = ''
 
 try: 
+    netmask = socket.gethostbyname( netmask )
     gateway = socket.gethostbyname( gateway )
+    myip = vfr_ipaddr[0]
+
 except NameError:
+    netmask = XenoUtil.get_current_ipmask()
     gateway = XenoUtil.get_current_ipgw()
 
-localip=''
-for i in vfr_ipaddr:
-    if XenoUtil.check_subnet(i,'169.254.0.0','255.255.0.0'): localip=i
-
-# Try to guess the machine's LAN settings
+# if we haven't got an address, see if we have one that matches the LAN
 
-lanip=''
-if netmask and gateway:
-    for i in vfr_ipaddr:
-       if XenoUtil.check_subnet(i,gateway,netmask): 
-           lanip=i
-           break
+if not myip:
+    if netmask and gateway:
+       for i in vfr_ipaddr:
+           if XenoUtil.check_subnet(i,gateway,netmask): 
+               myip=i
+               break
 
-# Have a fall back plan...
+# if we still haven't got an address, see if there's a link local one
 
-if not netmask:
-    netmask = '255.255.0.0' 
+if not myip and localip:
+    myip = localip
+    netmask = '255.255.0.0'
+    gateway = '169.254.1.0'
 
-if not gateway:
-    gateway = '169.254.1.0' 
 
-if not lanip:
-    lanip = vfr_ipaddr[0]
+# As a final fallback, through everything down the interface
 
+if not myip:
+    myip = vfr_ipaddr[0]
+    netmask = '0.0.0.0' 
+    gateway = '' 
 
 # Calculate the components with which we will build the command line
 
 nfsserv = '169.254.1.0'  
 
-cmdline_ip="ip="+lanip+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off"
+cmdline_ip="ip="+myip+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off"
 cmdline_root  = "root=/dev/ram0 rw init=/linuxrc"
 
 if localip:
diff --git a/tools/examples/netbsd b/tools/examples/netbsd
new file mode 100644 (file)
index 0000000..6050c8b
--- /dev/null
@@ -0,0 +1,113 @@
+
+##### Edit this python file to reflect the configuration of your system
+
+##### This example script expects a variable called 'vmid' to be set.
+
+def config_usage ():
+    print >>sys.stderr,"""
+The config file '%s' requires the following variable to be defined:
+ vmid             -- Numeric identifier for the new domain, used to calculate
+                     the VM's IP address and root partition. E.g. -Dvmid=1
+
+Additionally the following variable may be defined:
+ image            -- Path to kernel image, can be gzip'ed. [/boot/netbsd]
+ mem              -- Memory size. [16]
+ name             -- Domain name. [NetBSD VM vmid]
+ ip               -- Primary IP address for domain. [this domain's IP + vmid]
+ nfsserv          -- NFS server IP address. [169.254.1.0]
+ nfsroot          -- Path to nfs root filesystem. [/netboot/netbsd]
+""" % config_file
+
+
+try:
+    vmid=int(vmid) # convert to integer
+except:
+    print >>sys.stderr,"%s: This script expects 'vmid' to be set using -D vmid=X" % config_file
+    assert()
+
+if vmid == 0:
+    print >>sys.stderr,"%s: 'vmid' must be greater than 0" % config_file
+    assert()
+
+
+# STEP 1. Specify kernel image file. Can be gzip'ed.
+if image == "": image = "/boot/netbsd"
+
+builder_fn='netbsd' # this is a NetBSD domain
+
+
+# STEP 2. The initial memory allocation (in megabytes) for the new domain.
+try:
+    mem_size = int(mem)
+except:
+    mem_size = 16
+
+
+# STEP 3. A handy name for your new domain.
+try:
+    domain_name = name
+except:
+    domain_name = "NetBSD VM %d" % vmid
+
+
+# STEP 4. Specify IP address(es), for the new domain.  You need to
+# configure IP addrs within the domain just as you do normally.  This
+# is just to let Xen know about them so it can route packets
+# appropriately.
+
+#vfr_ipaddr = ["111.222.333.444","222.333.444.555"]
+try:
+    vfr_ipaddr = [ip, XenoUtil.add_offset_to_ip('169.254.1.0',vmid),]
+except:
+    vfr_ipaddr = [XenoUtil.add_offset_to_ip(XenoUtil.get_current_ipaddr(),vmid),
+                  XenoUtil.add_offset_to_ip('169.254.1.0',vmid),]
+
+
+# STEP 5a. Identify any physcial partitions or virtual disks you want the
+# domain to have access to, and what you want them accessible as
+# e.g. vbd_list = [ ('phy:sda1','sda1', 'w'),
+#       ('phy:sda%d' % (3+vmid), 'hda2', 'r'), 
+#       ('vd:as73gd784dh','hda1','w'),
+#       ('phy:cdrom','hdd','r')
+
+#vbd_list = [ ('phy:sda%d'%(7+vmid),'sda1','w' ), 
+#           ('phy:sda6','sda6','r') ]
+
+
+
+# STEP 5b. Set the VBD expertise level.  Most people should leave this
+# on 0, at least to begin with - this script can detect most dangerous
+# disk sharing between domains and with this set to zero it will only
+# allow read only sharing.
+
+vbd_expert = 0
+
+
+# STEP 6. Build the command line for the new domain. Edit as req'd.
+# You only need the ip= line if you're NFS booting or the root file system
+# doesn't set it later e.g. in ifcfg-eth0 or via DHCP
+# You can use 'extrabit' to set the runlevel and custom environment
+# variables used by custom rc scripts (e.g. VMID=, usr= )
+
+netmask = XenoUtil.get_current_ipmask()
+gateway = XenoUtil.get_current_ipgw()
+try:
+    nfsserv
+except:
+    nfsserv = '169.254.1.0'
+
+cmdline_ip = "ip="+vfr_ipaddr[0]+":"+nfsserv+":"+gateway+":"+netmask+"::eth0:off"
+try:
+    cmdline_root = "nfsroot="+nfsserv+":"+nfsroot
+except:
+    cmdline_root = "nfsroot="+nfsserv+":/netboot/netbsd"
+    #cmdline_root = "nfsroot=/full/path/to/root/directory"
+
+cmdline_extra = "bootdev=xennet0"
+
+
+# STEP 7. Set according to whether you want the script to watch the domain 
+# and auto-restart it should it die or exit.
+
+auto_restart = False
+#auto_restart = True
index 540d9d3c1ca97ea326b00e413f0035df254d0411..bac31cdd21ff33b3c3d0b39872a0b89627d75f33 100755 (executable)
@@ -11,11 +11,13 @@ Usage: %s [command] <params>
 
   stop      [dom]        -- pause a domain
   start     [dom]        -- un-pause a domain
-  shutdown  [dom]        -- request a domain to shutdown
+  shutdown  [dom] [[-w]] -- request a domain to shutdown (can specify 'all')
+                            (optionally wait for complete shutdown)
   destroy   [dom]        -- immediately terminate a domain
   pincpu    [dom] [cpu]  -- pin a domain to the specified CPU
-  save      [dom] [file] -- suspend a domain's memory to file
-  restore   [file]       -- resume a domain from a file
+  suspend   [dom] [file] -- write domain's memory to a file and terminate
+                           (resume by re-running xc_dom_create with -L option)
+  unwatch   [dom]        -- kill the auto-restart daemon for a domain
   list                   -- print info about all domains
   listvbds               -- print info about all virtual block devs
   cpu_bvtset [dom] [mcuadv] [warp] [warpl] [warpu]
@@ -30,7 +32,7 @@ Usage: %s [command] <params>
   vbd_remove [dom] [dev] -- remove disk or partition attached as 'dev' 
 """ % sys.argv[0]
 
-import Xc, sys, re, string
+import Xc, sys, re, string, time, os, signal
 
 if len(sys.argv) < 2:
     usage()
@@ -41,6 +43,8 @@ cmd = sys.argv[1]
 
 xc = Xc.new()
 rc = ''
+dom = None
+
 
 if len( sys.argv ) > 2 and re.match('\d+$', sys.argv[2]):
     dom = string.atoi(sys.argv[2])
@@ -52,7 +56,24 @@ elif cmd == 'start':
     rc = xc.domain_start( dom=dom )    
 
 elif cmd == 'shutdown':
-    rc = xc.domain_destroy( dom=dom, force=0 )    
+    list = []
+    if dom != None:
+        rc = xc.domain_destroy( dom=dom, force=0 )
+        list.append(dom)
+    elif sys.argv[2] == 'all':
+        for i in xc.domain_getinfo():
+            if i['dom'] != 0: # don't shutdown dom0!
+                ret = xc.domain_destroy( dom=i['dom'], force=0 )
+                if ret !=0: rc = ret
+                else: list.append(i['dom'])
+
+    if len(sys.argv) == 4 and sys.argv[3] == "-w":
+        # wait for all domains we shut down to terminate
+        for dom in list:
+            while True:
+                info = xc.domain_getinfo(dom,1)
+                if not ( info != [] and info[0]['dom'] == dom ): break
+                time.sleep(1)
 
 elif cmd == 'destroy':
     rc = xc.domain_destroy( dom=dom, force=1 )    
@@ -76,27 +97,55 @@ elif cmd == 'pincpu':
        xc.domain_start( dom=dom )
 
 elif cmd == 'list':
-    for i in xc.domain_getinfo(): print i
+    print 'Dom  Name             Mem(kb)  CPU  State  Time(s)'
+    for domain in xc.domain_getinfo():
 
-elif cmd == 'listvbds':
-    for i in xc.vbd_probe(): print i
+       run = (domain['running'] and 'r') or '-'                # domain['running'] ? run='r' : run='-'
+       stop = (domain['stopped'] and 's') or '-'               # domain['stopped'] ? stop='s': stop='-'
+
+        domain['state'] = run + stop
+        domain['cpu_time'] = domain['cpu_time']/1e8
+
+        print "%(dom)-4d %(name)-16s %(mem_kb)7d %(cpu)3d %(state)5s %(cpu_time)8d" % domain
+
+elif cmd == 'unwatch':
 
-elif cmd == 'save':
+    # the auto-restart daemon's pid file
+    watcher = '/var/run/xendomains/%d.pid' % dom
+
+    if os.path.isfile(watcher):
+        fd = open(watcher,'r')
+        pid = int(fd.readline())
+        os.kill(pid, signal.SIGTERM)
+
+elif cmd == 'listvbds':
+    vbdInfo = xc.vbd_probe()
+    for vbd in vbdInfo:
+        print 'dom:' + str(vbd['dom'])
+       del vbd['dom']
+        print '-----'
+        for field in vbd:
+                print field + ': ' + str(vbd[field])
+        print '\n'
+
+elif cmd == 'suspend':
     if len(sys.argv) < 4:
         usage()
         sys.exit(-1)
 
     file = sys.argv[3]
-        
-    rc = xc.linux_save( dom=dom, state_file=file, progress=1)
 
-elif cmd == 'restore':
-    if len(sys.argv) < 3:
-        usage()
-        sys.exit(-1)
-        
-    file = sys.argv[2]
-    rc = xc.linux_restore( state_file=file, progress=1 )
+    # the auto-restart daemon's pid file
+    watcher = '/var/run/xendomains/%d.pid' % dom
+
+    if os.path.isfile(watcher):
+        fd = open(watcher,'r')
+        pid = int(fd.readline())
+        os.kill(pid, signal.SIGTERM)
+
+    xc.domain_stop( dom=dom )
+    rc = xc.linux_save( dom=dom, state_file=file, progress=1)
+    if rc == 0 : xc.domain_destroy( dom=dom, force=1 )
 
 elif cmd == 'cpu_bvtslice':
     if len(sys.argv) < 3:
@@ -164,7 +213,8 @@ elif cmd == 'vif_getsched':
 
 
 elif cmd == 'vbd_add':
-
+    import XenoUtil
+    
     XenoUtil.VBD_EXPERT_LEVEL = 0 # sets the allowed level of potentially unsafe mappings
 
     if len(sys.argv) < 6:
@@ -196,6 +246,7 @@ elif cmd == 'vbd_add':
     print "Added disk/partition %s to domain %d as device %s (%x)" % (uname, dom, dev, virt_dev)
 
 elif cmd == 'vbd_remove':
+    import XenoUtil
 
     if len(sys.argv) < 4:
        usage()
index 6eaeb3471506798259770b229669caa7779877ad..43d9e7ec0f112557f57c0a791530232c1a2a3dbd 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-import Xc, XenoUtil, string, sys, os, time, socket, getopt
+import Xc, XenoUtil, string, sys, os, time, socket, getopt, signal, syslog
 
 config_dir  = '/etc/xc/'
 config_file = xc_config_file = config_dir + 'defaults'
@@ -18,10 +18,12 @@ in [] brackets. Arguments are as follows:
 Arguments to control the parsing of the defaults file:
  -f config_file   -- Use the specified defaults script. 
                      Default: ['%s']
+ -L state_file    -- Load virtual machine memory state from state_file
  -D foo=bar       -- Set variable foo=bar before parsing config
-                     E.g. '-D vmid=3:ip=1.2.3.4'
+                     E.g. '-D vmid=3;ip=1.2.3.4'
  -h               -- Print extended help message, including all arguments
  -n               -- Dry run only, don't actually create domain
+ -q               -- Quiet - write output only to the system log
 """ % (sys.argv[0], xc_config_file)
 
 def extra_usage ():
@@ -36,8 +38,8 @@ Arguments to override current config read from '%s':
  -e vbd_expert    -- Saftey catch to avoid some disk accidents ['%d'] 
  -d udisk,dev,rw  -- Add disk, partition, or virtual disk to domain. E.g. to 
                      make partion sda4 available to the domain as hda1 with 
-                     read-write access: '-b phy:sda4,hda1,rw' To add 
-                     multiple disks use multiple -d flags or seperate with ':'
+                     read-write access: '-d phy:sda4,hda1,rw' To add 
+                     multiple disks use multiple -d flags or seperate with ';'
                      Default: ['%s']
  -i vfr_ipaddr    -- Add IP address to the list which Xen will route to
                      the domain. Use multiple times to add more IP addrs.
@@ -68,30 +70,38 @@ def answer ( s ):
 def printvbds ( v ):
     s=''
     for (a,b,c) in v:
-       s = s + ':%s,%s,%s' % (a,b,c)
-    return s[1:]
-
-
-bail=False; dryrun=False; extrahelp=False
-image=''; ramdisk=''; builder_fn=''; 
-mem_size=0; domain_name=''; vfr_ipaddr=[]; 
-vbd_expert=0; auto_restart=0;
+       s = s + '; %s,%s,%s' % (a,b,c)
+    return s[2:]
+
+def output(string):
+    global quiet
+    syslog.syslog(string)
+    if not quiet:
+        print string
+    return
+
+bail=False; dryrun=False; extrahelp=False; quiet = False
+image=''; ramdisk=''; builder_fn=''; restore=0; state_file=''
+mem_size=0; domain_name=''; vfr_ipaddr=[];
+vbd_expert=0; auto_restart=False;
 vbd_list = []; cmdline_ip = ''; cmdline_root=''; cmdline_extra=''
 
 ##### Determine location of defautls file
 #####
 
 try:
-    opts, args = getopt.getopt(sys.argv[1:], "h?nf:D:k:r:b:m:N:a:e:d:i:I:R:E:" )
+    opts, args = getopt.getopt(sys.argv[1:], "h?nqf:D:k:r:b:m:N:a:e:d:i:I:R:E:L:" )
 
     for opt in opts:
        if opt[0] == '-f': config_file= opt[1]
        if opt[0] == '-h' or opt[0] == '-?' : bail=True; extrahelp=True
        if opt[0] == '-n': dryrun=True
        if opt[0] == '-D': 
-           for o in string.split( opt[1], ':' ):
+           for o in string.split( opt[1], ';' ):
                (l,r) = string.split( o, '=' )
                exec "%s='%s'" % (l,r)
+        if opt[0] == '-q': quiet = True
+        if opt[0] == '-L': restore = True; state_file = opt[1]
 
 
 except getopt.GetoptError:
@@ -113,7 +123,8 @@ except:
 ##### Parse the config file
 #####
 
-print "Parsing config file '%s'" % config_file
+if not quiet:
+    print "Parsing config file '%s'" % config_file
 
 try:
     execfile ( config_file )
@@ -139,7 +150,7 @@ x_vfr_ipaddr  = []
 for opt in opts:
     if opt[0] == '-k': image = opt[1]
     if opt[0] == '-r': ramdisk = opt[1]
-    if opt[0] == '-b': builder_fn = opt[1]  #XXXX
+    if opt[0] == '-b': builder_fn = opt[1]  
     if opt[0] == '-m': mem_size = int(opt[1])
     if opt[0] == '-N': domain_name = opt[1]
     if opt[0] == '-a': auto_restart = answer(opt[1])
@@ -150,7 +161,7 @@ for opt in opts:
     if opt[0] == '-i': x_vfr_ipaddr.append(opt[1])
     if opt[0] == '-d':
        try:
-           vv = string.split(opt[1],':')           
+           vv = string.split(opt[1],';')           
            for v in vv:
                (udisk,dev,mode) = string.split(v,',')
                x_vbd_list.append( (udisk,dev,mode) )
@@ -163,17 +174,18 @@ if x_vfr_ipaddr: vfr_ipaddr = x_vfr_ipaddr
 
 cmdline = cmdline_ip +' '+ cmdline_root +' '+ cmdline_extra
 
+syslog.openlog('xc_dom_create.py %s' % config_file, 0, syslog.LOG_DAEMON)
+
 ##### Print some debug info just incase things don't work out...
 ##### 
 
-print
-print 'VM image           : "%s"' % image
-print 'VM ramdisk         : "%s"' % ramdisk
-print 'VM memory (MB)     : "%d"' % mem_size
-print 'VM IP address(es)  : "%s"' % reduce((lambda a,b: a+':'+b),vfr_ipaddr,'' )[1:]
-print 'VM block device(s) : "%s"' % printvbds( vbd_list )
-print 'VM cmdline         : "%s"' % cmdline
-print
+output('VM image           : "%s"' % image)
+output('VM ramdisk         : "%s"' % ramdisk)
+output('VM memory (MB)     : "%d"' % mem_size)
+output('VM IP address(es)  : "%s"'
+                % reduce((lambda a,b: a+'; '+b),vfr_ipaddr,'' )[2:])
+output('VM block device(s) : "%s"' % printvbds( vbd_list ))
+output('VM cmdline         : "%s"' % cmdline)
 
 if dryrun:
     sys.exit(1)
@@ -194,7 +206,7 @@ def make_domain():
 
     # set up access to the global variables declared above
     global image, ramdisk, mem_size, domain_name, vfr_ipaddr, netmask
-    global vbd_list, cmdline, xc, vbd_expert
+    global vbd_list, cmdline, xc, vbd_expert, builder_fn
        
     if not os.path.isfile( image ):
         print "Image file '" + image + "' does not exist"
@@ -204,18 +216,25 @@ def make_domain():
         print "Ramdisk file '" + ramdisk + "' does not exist"
         sys.exit()
 
-    id = xc.domain_create( mem_kb=mem_size*1024, name=domain_name )
-    if id <= 0:
-        print "Error creating domain"
-        sys.exit()
-
-    ret = xc.linux_build( dom=id, image=image, ramdisk=ramdisk, 
-                         cmdline=cmdline )
-    if ret < 0:
-        print "Error building Linux guest OS: "
-        print "Return code from linux_build = " + str(ret)
-        xc.domain_destroy ( dom=id )
-        sys.exit()
+    if restore:
+        ret = eval('xc.%s_restore ( state_file=state_file, progress=1 )' % builder_fn)
+        if ret < 0:
+            print "Error restoring domain"
+            sys.exit()
+        else:
+            id = ret
+    else:
+        id = xc.domain_create( mem_kb=mem_size*1024, name=domain_name )
+        if id <= 0:
+            print "Error creating domain"
+            sys.exit()
+            
+        ret = eval('xc.%s_build ( dom=id, image=image, ramdisk=ramdisk, cmdline=cmdline )' % builder_fn)
+        if ret < 0:
+            print "Error building Linux guest OS: "
+            print "Return code = " + str(ret)
+            xc.domain_destroy ( dom=id )
+            sys.exit()
 
     # setup the virtual block devices
 
@@ -261,13 +280,33 @@ def make_domain():
     return id
 # end of make_domain()
 
+def mkpidfile():
+    global current_id
+    if not os.path.isdir('/var/run/xendomains/'):
+        os.mkdir('/var/run/xendomains/')
 
+    fd = open('/var/run/xendomains/%d.pid' % current_id, 'w')
+    print >> fd, str(os.getpid())
+    fd.close()
+    return
+
+def rmpidfile():
+    global current_id
+    os.unlink('/var/run/xendomains/%d.pid' % current_id)
+
+def death_handler(dummy1,dummy2):
+    global current_id
+    os.unlink('/var/run/xendomains/%d.pid' % current_id)
+    output('Auto-restart daemon: daemon PID = %d for domain %d is now exiting'
+              % (os.getpid(),current_id))
+    sys.exit(0)
+    return
 
 # The starting / monitoring of the domain actually happens here...
 
 # start the domain and record its ID number
 current_id = make_domain()
-print "VM started in domain %d" % current_id
+output("VM started in domain %d" % current_id)
 
 # if the auto_restart flag is set then keep polling to see if the domain is
 # alive - restart if it is not by calling make_domain() again (it's necessary
@@ -282,15 +321,22 @@ if auto_restart:
        os.setsid()
        pid = os.fork()
        if pid > 0:
-           print >> sys.stderr, 'Auto-restart daemon PID = %d' % pid
+            output('Auto-restart daemon PID = %d' % pid)
            sys.exit(0)
-    except:
-       print >> sys.stderr, 'Problem starting daemon'
+        signal.signal(signal.SIGTERM,death_handler)
+    except OSError:
+       print >> sys.stderr, 'Problem starting auto-restart daemon'
        sys.exit(1)
 
-    while auto_restart:
+    mkpidfile()
+
+    while True:
        time.sleep(1)
-       if not xc.domain_getinfo(current_id):
-           print "Domain %d has terminated, restarting VM in new domain" % current_id
+        info = xc.domain_getinfo(current_id, 1)
+       if info == [] or info[0]['dom'] != current_id:
+           output("Auto-restart daemon: Domain %d has terminated, restarting VM in new domain"
+                                     % current_id)
+            rmpidfile()
            current_id = make_domain()
-           print "VM started in domain %d" % current_id
+            mkpidfile()
+           output("Auto-restart daemon: VM restarted in domain %d" % current_id)
diff --git a/tools/examples/xendomains b/tools/examples/xendomains
new file mode 100755 (executable)
index 0000000..8133bdf
--- /dev/null
@@ -0,0 +1,136 @@
+#!/bin/sh
+#
+# /etc/init.d/xendomains
+# Start / stop domains automatically when domain 0 boots / shuts down.
+#
+# chkconfig: 345 99 00
+# description: Start / stop Xen domains.
+#
+# This script offers fairly basic functionality.
+#
+# Based on the example in the "Designing High Quality Integrated Linux
+# Applications HOWTO" by Avi Alkalay
+# <http://www.tldp.org/HOWTO/HighQuality-Apps-HOWTO/>
+#
+
+RETVAL=0
+
+INITD=/etc/init.d/
+. $INITD/functions
+
+on_fn_exit()
+{
+    if [ $RETVAL -eq 0 ]; then
+       success
+    else
+       failure
+    fi
+    
+    echo
+}
+
+start() {
+    if [ -f /var/lock/subsys/xendomains ]; then return; fi
+
+    echo -n $"Starting auto Xen domains:"
+
+    # we expect config scripts for auto starting domains to be in
+    # /etc/xc/auto/ - they could just be symlinks to files elsewhere
+    if [ $(ls /etc/xc/auto/ | wc -l) -gt 0 ]; then
+       
+       # create all domains with config files in /etc/xc/auto
+       for dom in /etc/xc/auto/*; do
+           xc_dom_create.py -q -f $dom
+           if [ $? -ne 0 ]; then
+               RETVAL=$?
+           fi
+       done
+    fi
+
+    [ $RETVAL -eq 0 ] && touch /var/lock/subsys/xendomains
+
+    on_fn_exit
+}
+
+stop()
+{
+    # NB. this shuts down ALL Xen domains (politely), not just the ones in
+    # /etc/xc/auto/*
+    # This is because it's easier to do ;-) but arguably if this script is run
+    # on system shutdown then it's also the right thing to do.
+    
+    echo -n $"Shutting down all Xen domains:"
+
+    if [ $(ls /var/run/xendomains/ | wc -l) -gt 0 ]; then
+       
+       cd /var/run/xendomains/
+
+       for pid in *; do
+          
+           kill -s SIGTERM $(cat $pid)
+
+       done
+
+    fi
+
+    sleep 3 # avoid races
+
+    xc_dom_control.py shutdown all -w # shut down all domains, politely and wait
+                                      # for all to exit
+    
+    RETVAL=$?
+
+    [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/xendomains
+
+    on_fn_exit
+}
+
+# This does NOT necessarily restart all running domains: instead it
+# stops all running domains and then boots all the domains specified in
+# /etc/xc/auto.  If other domains have been started manually then they will
+# not get restarted.
+# Commented out to avoid confusion!
+#
+#restart()
+#{
+#    stop
+#    start
+#}
+
+# same as restart for now - commented out to avoid confusion
+#reload()
+#{
+#    restart
+#}
+
+
+case "$1" in
+    start)
+       start
+       ;;
+
+    stop)
+       stop
+       ;;
+
+# The following are commented out to disable them by default to avoid confusion
+# - see the notes above
+#
+#    restart)
+#      restart
+#      ;;
+#
+#    reload)
+#      reload
+#      ;;
+
+    status)
+       xc_dom_control.py list
+       ;;
+
+    *)
+       echo $"Usage: $0 {start|stop|status}"
+       ;;
+esac
+
+exit $RETVAL
index 246d9cfbf93ea0ee0cc6891c9504702d3c8af861..290d69649a59fe5626a7aa87e62eb362f994db62 100644 (file)
@@ -55,6 +55,11 @@ int xc_linux_build(int xc_handle,
                    const char *ramdisk_name,
                    const char *cmdline);
 
+int xc_netbsd_build(int xc_handle,
+                    unsigned int domid,
+                    const char *image_name,
+                    const char *cmdline);
+
 int xc_bvtsched_global_set(int xc_handle,
                            unsigned long ctx_allow);
 int xc_bvtsched_domain_set(int xc_handle,
diff --git a/tools/xc/lib/xc_elf.h b/tools/xc/lib/xc_elf.h
new file mode 100644 (file)
index 0000000..e0d0c26
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * Copyright (c) 1995, 1996 Erik Theisen.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+typedef u_int8_t       Elf_Byte;
+
+typedef u_int32_t      Elf32_Addr;     /* Unsigned program address */
+typedef u_int32_t      Elf32_Off;      /* Unsigned file offset */
+typedef int32_t                Elf32_Sword;    /* Signed large integer */
+typedef u_int32_t      Elf32_Word;     /* Unsigned large integer */
+typedef u_int16_t      Elf32_Half;     /* Unsigned medium integer */
+
+typedef u_int64_t      Elf64_Addr;
+typedef u_int64_t      Elf64_Off;
+typedef int32_t                Elf64_Shalf;
+
+typedef int32_t                Elf64_Sword;
+typedef u_int32_t      Elf64_Word;
+
+typedef int64_t                Elf64_Sxword;
+typedef u_int64_t      Elf64_Xword;
+
+typedef u_int32_t      Elf64_Half;
+typedef u_int16_t      Elf64_Quarter;
+
+/*
+ * e_ident[] identification indexes 
+ * See http://www.caldera.com/developers/gabi/2000-07-17/ch4.eheader.html
+ */
+#define EI_MAG0                0               /* file ID */
+#define EI_MAG1                1               /* file ID */
+#define EI_MAG2                2               /* file ID */
+#define EI_MAG3                3               /* file ID */
+#define EI_CLASS       4               /* file class */
+#define EI_DATA                5               /* data encoding */
+#define EI_VERSION     6               /* ELF header version */
+#define EI_OSABI       7               /* OS/ABI ID */
+#define EI_ABIVERSION  8               /* ABI version */ 
+#define EI_PAD         9               /* start of pad bytes */
+#define EI_NIDENT      16              /* Size of e_ident[] */
+
+/* e_ident[] magic number */
+#define        ELFMAG0         0x7f            /* e_ident[EI_MAG0] */
+#define        ELFMAG1         'E'             /* e_ident[EI_MAG1] */
+#define        ELFMAG2         'L'             /* e_ident[EI_MAG2] */
+#define        ELFMAG3         'F'             /* e_ident[EI_MAG3] */
+#define        ELFMAG          "\177ELF"       /* magic */
+#define        SELFMAG         4               /* size of magic */
+
+/* e_ident[] file class */
+#define        ELFCLASSNONE    0               /* invalid */
+#define        ELFCLASS32      1               /* 32-bit objs */
+#define        ELFCLASS64      2               /* 64-bit objs */
+#define        ELFCLASSNUM     3               /* number of classes */
+
+/* e_ident[] data encoding */
+#define ELFDATANONE    0               /* invalid */
+#define ELFDATA2LSB    1               /* Little-Endian */
+#define ELFDATA2MSB    2               /* Big-Endian */
+#define ELFDATANUM     3               /* number of data encode defines */
+
+/* e_ident[] Operating System/ABI */
+#define ELFOSABI_SYSV          0       /* UNIX System V ABI */
+#define ELFOSABI_HPUX          1       /* HP-UX operating system */
+#define ELFOSABI_NETBSD                2       /* NetBSD */
+#define ELFOSABI_LINUX         3       /* GNU/Linux */
+#define ELFOSABI_HURD          4       /* GNU/Hurd */
+#define ELFOSABI_86OPEN                5       /* 86Open common IA32 ABI */
+#define ELFOSABI_SOLARIS       6       /* Solaris */
+#define ELFOSABI_MONTEREY      7       /* Monterey */
+#define ELFOSABI_IRIX          8       /* IRIX */
+#define ELFOSABI_FREEBSD       9       /* FreeBSD */
+#define ELFOSABI_TRU64         10      /* TRU64 UNIX */
+#define ELFOSABI_MODESTO       11      /* Novell Modesto */
+#define ELFOSABI_OPENBSD       12      /* OpenBSD */
+#define ELFOSABI_ARM           97      /* ARM */
+#define ELFOSABI_STANDALONE    255     /* Standalone (embedded) application */
+
+/* e_ident */
+#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+                      (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+                      (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+                      (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+/* ELF Header */
+typedef struct elfhdr {
+       unsigned char   e_ident[EI_NIDENT]; /* ELF Identification */
+       Elf32_Half      e_type;         /* object file type */
+       Elf32_Half      e_machine;      /* machine */
+       Elf32_Word      e_version;      /* object file version */
+       Elf32_Addr      e_entry;        /* virtual entry point */
+       Elf32_Off       e_phoff;        /* program header table offset */
+       Elf32_Off       e_shoff;        /* section header table offset */
+       Elf32_Word      e_flags;        /* processor-specific flags */
+       Elf32_Half      e_ehsize;       /* ELF header size */
+       Elf32_Half      e_phentsize;    /* program header entry size */
+       Elf32_Half      e_phnum;        /* number of program header entries */
+       Elf32_Half      e_shentsize;    /* section header entry size */
+       Elf32_Half      e_shnum;        /* number of section header entries */
+       Elf32_Half      e_shstrndx;     /* section header table's "section 
+                                          header string table" entry offset */
+} Elf32_Ehdr;
+
+typedef struct {
+       unsigned char   e_ident[EI_NIDENT];     /* Id bytes */
+       Elf64_Quarter   e_type;                 /* file type */
+       Elf64_Quarter   e_machine;              /* machine type */
+       Elf64_Half      e_version;              /* version number */
+       Elf64_Addr      e_entry;                /* entry point */
+       Elf64_Off       e_phoff;                /* Program hdr offset */
+       Elf64_Off       e_shoff;                /* Section hdr offset */
+       Elf64_Half      e_flags;                /* Processor flags */
+       Elf64_Quarter   e_ehsize;               /* sizeof ehdr */
+       Elf64_Quarter   e_phentsize;            /* Program header entry size */
+       Elf64_Quarter   e_phnum;                /* Number of program headers */
+       Elf64_Quarter   e_shentsize;            /* Section header entry size */
+       Elf64_Quarter   e_shnum;                /* Number of section headers */
+       Elf64_Quarter   e_shstrndx;             /* String table index */
+} Elf64_Ehdr;
+
+/* e_type */
+#define ET_NONE                0               /* No file type */
+#define ET_REL         1               /* relocatable file */
+#define ET_EXEC                2               /* executable file */
+#define ET_DYN         3               /* shared object file */
+#define ET_CORE                4               /* core file */
+#define ET_NUM         5               /* number of types */
+#define ET_LOPROC      0xff00          /* reserved range for processor */
+#define ET_HIPROC      0xffff          /*  specific e_type */
+
+/* e_machine */
+#define EM_NONE                0               /* No Machine */
+#define EM_M32         1               /* AT&T WE 32100 */
+#define EM_SPARC       2               /* SPARC */
+#define EM_386         3               /* Intel 80386 */
+#define EM_68K         4               /* Motorola 68000 */
+#define EM_88K         5               /* Motorola 88000 */
+#define EM_486         6               /* Intel 80486 - unused? */
+#define EM_860         7               /* Intel 80860 */
+#define EM_MIPS                8               /* MIPS R3000 Big-Endian only */
+/* 
+ * Don't know if EM_MIPS_RS4_BE,
+ * EM_SPARC64, EM_PARISC,
+ * or EM_PPC are ABI compliant
+ */
+#define EM_MIPS_RS4_BE 10              /* MIPS R4000 Big-Endian */
+#define EM_SPARC64     11              /* SPARC v9 64-bit unoffical */
+#define EM_PARISC      15              /* HPPA */
+#define EM_SPARC32PLUS 18              /* Enhanced instruction set SPARC */
+#define EM_PPC         20              /* PowerPC */
+#define EM_ARM         40              /* Advanced RISC Machines ARM */
+#define EM_ALPHA       41              /* DEC ALPHA */
+#define EM_SPARCV9     43              /* SPARC version 9 */
+#define EM_ALPHA_EXP   0x9026          /* DEC ALPHA */
+#define EM_X86_64      62              /* AMD x86-64 architecture */
+#define EM_VAX         75              /* DEC VAX */
+#define EM_NUM         15              /* number of machine types */
+
+/* Version */
+#define EV_NONE                0               /* Invalid */
+#define EV_CURRENT     1               /* Current */
+#define EV_NUM         2               /* number of versions */
+
+/* Section Header */
+typedef struct {
+       Elf32_Word      sh_name;        /* name - index into section header
+                                          string table section */
+       Elf32_Word      sh_type;        /* type */
+       Elf32_Word      sh_flags;       /* flags */
+       Elf32_Addr      sh_addr;        /* address */
+       Elf32_Off       sh_offset;      /* file offset */
+       Elf32_Word      sh_size;        /* section size */
+       Elf32_Word      sh_link;        /* section header table index link */
+       Elf32_Word      sh_info;        /* extra information */
+       Elf32_Word      sh_addralign;   /* address alignment */
+       Elf32_Word      sh_entsize;     /* section entry size */
+} Elf32_Shdr;
+
+typedef struct {
+       Elf64_Half      sh_name;        /* section name */
+       Elf64_Half      sh_type;        /* section type */
+       Elf64_Xword     sh_flags;       /* section flags */
+       Elf64_Addr      sh_addr;        /* virtual address */
+       Elf64_Off       sh_offset;      /* file offset */
+       Elf64_Xword     sh_size;        /* section size */
+       Elf64_Half      sh_link;        /* link to another */
+       Elf64_Half      sh_info;        /* misc info */
+       Elf64_Xword     sh_addralign;   /* memory alignment */
+       Elf64_Xword     sh_entsize;     /* table entry size */
+} Elf64_Shdr;
+
+/* Special Section Indexes */
+#define SHN_UNDEF      0               /* undefined */
+#define SHN_LORESERVE  0xff00          /* lower bounds of reserved indexes */
+#define SHN_LOPROC     0xff00          /* reserved range for processor */
+#define SHN_HIPROC     0xff1f          /*   specific section indexes */
+#define SHN_ABS                0xfff1          /* absolute value */
+#define SHN_COMMON     0xfff2          /* common symbol */
+#define SHN_HIRESERVE  0xffff          /* upper bounds of reserved indexes */
+
+/* sh_type */
+#define SHT_NULL       0               /* inactive */
+#define SHT_PROGBITS   1               /* program defined information */
+#define SHT_SYMTAB     2               /* symbol table section */
+#define SHT_STRTAB     3               /* string table section */
+#define SHT_RELA       4               /* relocation section with addends*/
+#define SHT_HASH       5               /* symbol hash table section */
+#define SHT_DYNAMIC    6               /* dynamic section */
+#define SHT_NOTE       7               /* note section */
+#define SHT_NOBITS     8               /* no space section */
+#define SHT_REL                9               /* relation section without addends */
+#define SHT_SHLIB      10              /* reserved - purpose unknown */
+#define SHT_DYNSYM     11              /* dynamic symbol table section */
+#define SHT_NUM                12              /* number of section types */
+#define SHT_LOPROC     0x70000000      /* reserved range for processor */
+#define SHT_HIPROC     0x7fffffff      /*  specific section header types */
+#define SHT_LOUSER     0x80000000      /* reserved range for application */
+#define SHT_HIUSER     0xffffffff      /*  specific indexes */
+
+/* Section names */
+#define ELF_BSS         ".bss"         /* uninitialized data */
+#define ELF_DATA        ".data"                /* initialized data */
+#define ELF_DEBUG       ".debug"       /* debug */
+#define ELF_DYNAMIC     ".dynamic"     /* dynamic linking information */
+#define ELF_DYNSTR      ".dynstr"      /* dynamic string table */
+#define ELF_DYNSYM      ".dynsym"      /* dynamic symbol table */
+#define ELF_FINI        ".fini"                /* termination code */
+#define ELF_GOT         ".got"         /* global offset table */
+#define ELF_HASH        ".hash"                /* symbol hash table */
+#define ELF_INIT        ".init"                /* initialization code */
+#define ELF_REL_DATA    ".rel.data"    /* relocation data */
+#define ELF_REL_FINI    ".rel.fini"    /* relocation termination code */
+#define ELF_REL_INIT    ".rel.init"    /* relocation initialization code */
+#define ELF_REL_DYN     ".rel.dyn"     /* relocaltion dynamic link info */
+#define ELF_REL_RODATA  ".rel.rodata"  /* relocation read-only data */
+#define ELF_REL_TEXT    ".rel.text"    /* relocation code */
+#define ELF_RODATA      ".rodata"      /* read-only data */
+#define ELF_SHSTRTAB    ".shstrtab"    /* section header string table */
+#define ELF_STRTAB      ".strtab"      /* string table */
+#define ELF_SYMTAB      ".symtab"      /* symbol table */
+#define ELF_TEXT        ".text"                /* code */
+
+
+/* Section Attribute Flags - sh_flags */
+#define SHF_WRITE      0x1             /* Writable */
+#define SHF_ALLOC      0x2             /* occupies memory */
+#define SHF_EXECINSTR  0x4             /* executable */
+#define SHF_MASKPROC   0xf0000000      /* reserved bits for processor */
+                                       /*  specific section attributes */
+
+/* Symbol Table Entry */
+typedef struct elf32_sym {
+       Elf32_Word      st_name;        /* name - index into string table */
+       Elf32_Addr      st_value;       /* symbol value */
+       Elf32_Word      st_size;        /* symbol size */
+       unsigned char   st_info;        /* type and binding */
+       unsigned char   st_other;       /* 0 - no defined meaning */
+       Elf32_Half      st_shndx;       /* section header index */
+} Elf32_Sym;
+
+typedef struct {
+       Elf64_Half      st_name;        /* Symbol name index in str table */
+       Elf_Byte        st_info;        /* type / binding attrs */
+       Elf_Byte        st_other;       /* unused */
+       Elf64_Quarter   st_shndx;       /* section index of symbol */
+       Elf64_Xword     st_value;       /* value of symbol */
+       Elf64_Xword     st_size;        /* size of symbol */
+} Elf64_Sym;
+
+/* Symbol table index */
+#define STN_UNDEF      0               /* undefined */
+
+/* Extract symbol info - st_info */
+#define ELF32_ST_BIND(x)       ((x) >> 4)
+#define ELF32_ST_TYPE(x)       (((unsigned int) x) & 0xf)
+#define ELF32_ST_INFO(b,t)     (((b) << 4) + ((t) & 0xf))
+
+#define ELF64_ST_BIND(x)       ((x) >> 4)
+#define ELF64_ST_TYPE(x)       (((unsigned int) x) & 0xf)
+#define ELF64_ST_INFO(b,t)     (((b) << 4) + ((t) & 0xf))
+
+/* Symbol Binding - ELF32_ST_BIND - st_info */
+#define STB_LOCAL      0               /* Local symbol */
+#define STB_GLOBAL     1               /* Global symbol */
+#define STB_WEAK       2               /* like global - lower precedence */
+#define STB_NUM                3               /* number of symbol bindings */
+#define STB_LOPROC     13              /* reserved range for processor */
+#define STB_HIPROC     15              /*  specific symbol bindings */
+
+/* Symbol type - ELF32_ST_TYPE - st_info */
+#define STT_NOTYPE     0               /* not specified */
+#define STT_OBJECT     1               /* data object */
+#define STT_FUNC       2               /* function */
+#define STT_SECTION    3               /* section */
+#define STT_FILE       4               /* file */
+#define STT_NUM                5               /* number of symbol types */
+#define STT_LOPROC     13              /* reserved range for processor */
+#define STT_HIPROC     15              /*  specific symbol types */
+
+/* Relocation entry with implicit addend */
+typedef struct {
+       Elf32_Addr      r_offset;       /* offset of relocation */
+       Elf32_Word      r_info;         /* symbol table index and type */
+} Elf32_Rel;
+
+/* Relocation entry with explicit addend */
+typedef struct {
+       Elf32_Addr      r_offset;       /* offset of relocation */
+       Elf32_Word      r_info;         /* symbol table index and type */
+       Elf32_Sword     r_addend;
+} Elf32_Rela;
+
+/* Extract relocation info - r_info */
+#define ELF32_R_SYM(i)         ((i) >> 8)
+#define ELF32_R_TYPE(i)                ((unsigned char) (i))
+#define ELF32_R_INFO(s,t)      (((s) << 8) + (unsigned char)(t))
+
+typedef struct {
+       Elf64_Xword     r_offset;       /* where to do it */
+       Elf64_Xword     r_info;         /* index & type of relocation */
+} Elf64_Rel;
+
+typedef struct {
+       Elf64_Xword     r_offset;       /* where to do it */
+       Elf64_Xword     r_info;         /* index & type of relocation */
+       Elf64_Sxword    r_addend;       /* adjustment value */
+} Elf64_Rela;
+
+#define        ELF64_R_SYM(info)       ((info) >> 32)
+#define        ELF64_R_TYPE(info)      ((info) & 0xFFFFFFFF)
+#define ELF64_R_INFO(s,t)      (((s) << 32) + (u_int32_t)(t))
+
+/* Program Header */
+typedef struct {
+       Elf32_Word      p_type;         /* segment type */
+       Elf32_Off       p_offset;       /* segment offset */
+       Elf32_Addr      p_vaddr;        /* virtual address of segment */
+       Elf32_Addr      p_paddr;        /* physical address - ignored? */
+       Elf32_Word      p_filesz;       /* number of bytes in file for seg. */
+       Elf32_Word      p_memsz;        /* number of bytes in mem. for seg. */
+       Elf32_Word      p_flags;        /* flags */
+       Elf32_Word      p_align;        /* memory alignment */
+} Elf32_Phdr;
+
+typedef struct {
+       Elf64_Half      p_type;         /* entry type */
+       Elf64_Half      p_flags;        /* flags */
+       Elf64_Off       p_offset;       /* offset */
+       Elf64_Addr      p_vaddr;        /* virtual address */
+       Elf64_Addr      p_paddr;        /* physical address */
+       Elf64_Xword     p_filesz;       /* file size */
+       Elf64_Xword     p_memsz;        /* memory size */
+       Elf64_Xword     p_align;        /* memory & file alignment */
+} Elf64_Phdr;
+
+/* Segment types - p_type */
+#define PT_NULL                0               /* unused */
+#define PT_LOAD                1               /* loadable segment */
+#define PT_DYNAMIC     2               /* dynamic linking section */
+#define PT_INTERP      3               /* the RTLD */
+#define PT_NOTE                4               /* auxiliary information */
+#define PT_SHLIB       5               /* reserved - purpose undefined */
+#define PT_PHDR                6               /* program header */
+#define PT_NUM         7               /* Number of segment types */
+#define PT_LOPROC      0x70000000      /* reserved range for processor */
+#define PT_HIPROC      0x7fffffff      /*  specific segment types */
+
+/* Segment flags - p_flags */
+#define PF_X           0x1             /* Executable */
+#define PF_W           0x2             /* Writable */
+#define PF_R           0x4             /* Readable */
+#define PF_MASKPROC    0xf0000000      /* reserved bits for processor */
+                                       /*  specific segment flags */
+
+/* Dynamic structure */
+typedef struct {
+       Elf32_Sword     d_tag;          /* controls meaning of d_val */
+       union {
+               Elf32_Word      d_val;  /* Multiple meanings - see d_tag */
+               Elf32_Addr      d_ptr;  /* program virtual address */
+       } d_un;
+} Elf32_Dyn;
+
+typedef struct {
+       Elf64_Xword     d_tag;          /* controls meaning of d_val */
+       union {
+               Elf64_Addr      d_ptr;
+               Elf64_Xword     d_val;
+       } d_un;
+} Elf64_Dyn;
+
+/* Dynamic Array Tags - d_tag */
+#define DT_NULL                0               /* marks end of _DYNAMIC array */
+#define DT_NEEDED      1               /* string table offset of needed lib */
+#define DT_PLTRELSZ    2               /* size of relocation entries in PLT */
+#define DT_PLTGOT      3               /* address PLT/GOT */
+#define DT_HASH                4               /* address of symbol hash table */
+#define DT_STRTAB      5               /* address of string table */
+#define DT_SYMTAB      6               /* address of symbol table */
+#define DT_RELA                7               /* address of relocation table */
+#define DT_RELASZ      8               /* size of relocation table */
+#define DT_RELAENT     9               /* size of relocation entry */
+#define DT_STRSZ       10              /* size of string table */
+#define DT_SYMENT      11              /* size of symbol table entry */
+#define DT_INIT                12              /* address of initialization func. */
+#define DT_FINI                13              /* address of termination function */
+#define DT_SONAME      14              /* string table offset of shared obj */
+#define DT_RPATH       15              /* string table offset of library
+                                          search path */
+#define DT_SYMBOLIC    16              /* start sym search in shared obj. */
+#define DT_REL         17              /* address of rel. tbl. w addends */
+#define DT_RELSZ       18              /* size of DT_REL relocation table */
+#define DT_RELENT      19              /* size of DT_REL relocation entry */
+#define DT_PLTREL      20              /* PLT referenced relocation entry */
+#define DT_DEBUG       21              /* bugger */
+#define DT_TEXTREL     22              /* Allow rel. mod. to unwritable seg */
+#define DT_JMPREL      23              /* add. of PLT's relocation entries */
+#define DT_BIND_NOW    24              /* Bind now regardless of env setting */
+#define DT_NUM         25              /* Number used. */
+#define DT_LOPROC      0x70000000      /* reserved range for processor */
+#define DT_HIPROC      0x7fffffff      /*  specific dynamic array tags */
+       
+/* Standard ELF hashing function */
+unsigned int elf_hash(const unsigned char *name);
+
+/*
+ * Note Definitions
+ */
+typedef struct {
+       Elf32_Word namesz;
+       Elf32_Word descsz;
+       Elf32_Word type;
+} Elf32_Note;
+
+typedef struct {
+       Elf64_Half namesz;
+       Elf64_Half descsz;
+       Elf64_Half type;
+} Elf64_Note;
+
+
+#if defined(ELFSIZE)
+#define CONCAT(x,y)    __CONCAT(x,y)
+#define ELFNAME(x)     CONCAT(elf,CONCAT(ELFSIZE,CONCAT(_,x)))
+#define ELFNAME2(x,y)  CONCAT(x,CONCAT(_elf,CONCAT(ELFSIZE,CONCAT(_,y))))
+#define ELFNAMEEND(x)  CONCAT(x,CONCAT(_elf,ELFSIZE))
+#define ELFDEFNNAME(x) CONCAT(ELF,CONCAT(ELFSIZE,CONCAT(_,x)))
+#endif
+
+#if defined(ELFSIZE) && (ELFSIZE == 32)
+#define Elf_Ehdr       Elf32_Ehdr
+#define Elf_Phdr       Elf32_Phdr
+#define Elf_Shdr       Elf32_Shdr
+#define Elf_Sym                Elf32_Sym
+#define Elf_Rel                Elf32_Rel
+#define Elf_RelA       Elf32_Rela
+#define Elf_Dyn                Elf32_Dyn
+#define Elf_Word       Elf32_Word
+#define Elf_Sword      Elf32_Sword
+#define Elf_Addr       Elf32_Addr
+#define Elf_Off                Elf32_Off
+#define Elf_Nhdr       Elf32_Nhdr
+#define Elf_Note       Elf32_Note
+
+#define ELF_R_SYM      ELF32_R_SYM
+#define ELF_R_TYPE     ELF32_R_TYPE
+#define ELF_R_INFO     ELF32_R_INFO
+#define ELFCLASS       ELFCLASS32
+
+#define ELF_ST_BIND    ELF32_ST_BIND
+#define ELF_ST_TYPE    ELF32_ST_TYPE
+#define ELF_ST_INFO    ELF32_ST_INFO
+
+#define AuxInfo                Aux32Info
+#elif defined(ELFSIZE) && (ELFSIZE == 64)
+#define Elf_Ehdr       Elf64_Ehdr
+#define Elf_Phdr       Elf64_Phdr
+#define Elf_Shdr       Elf64_Shdr
+#define Elf_Sym                Elf64_Sym
+#define Elf_Rel                Elf64_Rel
+#define Elf_RelA       Elf64_Rela
+#define Elf_Dyn                Elf64_Dyn
+#define Elf_Word       Elf64_Word
+#define Elf_Sword      Elf64_Sword
+#define Elf_Addr       Elf64_Addr
+#define Elf_Off                Elf64_Off
+#define Elf_Nhdr       Elf64_Nhdr
+#define Elf_Note       Elf64_Note
+
+#define ELF_R_SYM      ELF64_R_SYM
+#define ELF_R_TYPE     ELF64_R_TYPE
+#define ELF_R_INFO     ELF64_R_INFO
+#define ELFCLASS       ELFCLASS64
+
+#define ELF_ST_BIND    ELF64_ST_BIND
+#define ELF_ST_TYPE    ELF64_ST_TYPE
+#define ELF_ST_INFO    ELF64_ST_INFO
+
+#define AuxInfo                Aux64Info
+#endif
+
diff --git a/tools/xc/lib/xc_netbsd_build.c b/tools/xc/lib/xc_netbsd_build.c
new file mode 100644 (file)
index 0000000..260c7e6
--- /dev/null
@@ -0,0 +1,694 @@
+/******************************************************************************
+ * xc_netbsd_build.c
+ */
+
+#include "xc_private.h"
+#define ELFSIZE 32             /* XXX */
+#include "xc_elf.h"
+#include <zlib.h>
+
+/* #define DEBUG 1 */
+
+#ifdef DEBUG
+#define DPRINTF(x) printf x
+#else
+#define DPRINTF(x)
+#endif
+
+static int loadelfimage(gzFile, int, unsigned long *, unsigned long,
+                       unsigned long *, unsigned long *,
+                       unsigned long *, unsigned long *);
+
+#define ELFROUND (ELFSIZE / 8)
+
+#define L1_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED)
+#define L2_PROT (_PAGE_PRESENT|_PAGE_RW|_PAGE_ACCESSED|_PAGE_DIRTY|_PAGE_USER)
+
+static long get_tot_pages(int xc_handle, int domid)
+{
+    dom0_op_t op;
+    op.cmd = DOM0_GETDOMAININFO;
+    op.u.getdomaininfo.domain = domid;
+    return (do_dom0_op(xc_handle, &op) < 0) ? 
+        -1 : op.u.getdomaininfo.tot_pages;
+}
+
+static int get_pfn_list(int xc_handle,
+                        int domid, 
+                        unsigned long *pfn_buf, 
+                        unsigned long max_pfns)
+{
+    dom0_op_t op;
+    int ret;
+    op.cmd = DOM0_GETMEMLIST;
+    op.u.getmemlist.domain   = domid;
+    op.u.getmemlist.max_pfns = max_pfns;
+    op.u.getmemlist.buffer   = pfn_buf;
+
+    if ( mlock(pfn_buf, max_pfns * sizeof(unsigned long)) != 0 )
+        return -1;
+
+    ret = do_dom0_op(xc_handle, &op);
+
+    (void)munlock(pfn_buf, max_pfns * sizeof(unsigned long));
+
+    return (ret < 0) ? -1 : op.u.getmemlist.num_pfns;
+}
+
+static int send_pgupdates(int xc_handle, mmu_update_t *updates, int nr_updates)
+{
+    int ret = -1;
+    privcmd_hypercall_t hypercall;
+
+    hypercall.op     = __HYPERVISOR_mmu_update;
+    hypercall.arg[0] = (unsigned long)updates;
+    hypercall.arg[1] = (unsigned long)nr_updates;
+
+    if ( mlock(updates, nr_updates * sizeof(*updates)) != 0 )
+        goto out1;
+
+    if ( do_xen_hypercall(xc_handle, &hypercall) < 0 )
+        goto out2;
+
+    ret = 0;
+
+ out2: (void)munlock(updates, nr_updates * sizeof(*updates));
+ out1: return ret;
+}
+
+static int setup_guestos(int xc_handle,
+                         int dom, 
+                         gzFile kernel_gfd, 
+                         unsigned long tot_pages,
+                         unsigned long *virt_startinfo_addr, 
+                         unsigned long *virt_load_addr, 
+                         dom0_builddomain_t *builddomain, 
+                         const char *cmdline,
+                         unsigned long shared_info_frame)
+{
+    l1_pgentry_t *vl1tab = NULL, *vl1e = NULL;
+    l2_pgentry_t *vl2tab = NULL, *vl2e = NULL;
+    unsigned long *page_array = NULL;
+    mmu_update_t *pgt_update_arr = NULL, *pgt_updates = NULL;
+    int alloc_index, num_pt_pages;
+    unsigned long l2tab;
+    unsigned long l1tab = 0;
+    unsigned long num_pgt_updates = 0;
+    unsigned long count, pt_start;
+    unsigned long symtab_addr = 0, symtab_len = 0;
+    start_info_t *start_info;
+    shared_info_t *shared_info;
+    unsigned long ksize;
+    int pm_handle;
+
+    memset(builddomain, 0, sizeof(*builddomain));
+
+    if ( (pm_handle = init_pfn_mapper()) < 0 )
+        goto error_out;
+
+    pgt_updates = malloc((tot_pages + 1024) * 3 * sizeof(mmu_update_t));
+    page_array = malloc(tot_pages * sizeof(unsigned long));
+    pgt_update_arr = pgt_updates;
+    if ( (pgt_update_arr == NULL) || (page_array == NULL) )
+    {
+        PERROR("Could not allocate memory");
+        goto error_out;
+    }
+
+    if ( get_pfn_list(xc_handle, dom, page_array, tot_pages) != tot_pages )
+    {
+        PERROR("Could not get the page frame list");
+        goto error_out;
+    }
+
+    if (loadelfimage(kernel_gfd, pm_handle, page_array, tot_pages,
+                    virt_load_addr, &ksize, &symtab_addr, &symtab_len))
+       goto error_out;
+
+    /* ksize is kernel-image size rounded up to a page boundary. */
+
+    alloc_index = tot_pages - 1;
+
+    /* Count bottom-level PTs, rounding up. */
+    num_pt_pages = (l1_table_offset(*virt_load_addr) + tot_pages + 1023) / 1024;
+
+    /* We must also count the page directory. */
+    num_pt_pages++;
+
+    /* Index of first PT page. */
+    pt_start = tot_pages - num_pt_pages;
+
+    /*
+     * First allocate page for page dir. Allocation goes backwards from the end
+     * of the allocated physical address space.
+     */
+    l2tab = page_array[alloc_index] << PAGE_SHIFT;
+    alloc_index--;
+    builddomain->ctxt.pt_base = l2tab;
+
+    /*
+     * Pin down l2tab addr as page dir page - causes hypervisor to provide
+     * correct protection for the page
+     */ 
+    pgt_updates->ptr = l2tab | MMU_EXTENDED_COMMAND;
+    pgt_updates->val = MMUEXT_PIN_L2_TABLE;
+    pgt_updates++;
+    num_pgt_updates++;
+
+    /* Initialise the page tables. */
+    if ( (vl2tab = map_pfn(pm_handle, l2tab >> PAGE_SHIFT)) == NULL )
+        goto error_out;
+    memset(vl2tab, 0, PAGE_SIZE);
+    vl2e = vl2tab + l2_table_offset(*virt_load_addr);
+    for ( count = 0; count < tot_pages; count++ )
+    {    
+        if ( ((unsigned long)vl1e & (PAGE_SIZE-1)) == 0 ) 
+        {
+            l1tab = page_array[alloc_index] << PAGE_SHIFT;
+            if ( (vl1tab = map_pfn(pm_handle, l1tab >> PAGE_SHIFT)) == NULL )
+                goto error_out;
+            memset(vl1tab, 0, PAGE_SIZE);
+            alloc_index--;
+               
+            vl1e = vl1tab + l1_table_offset(*virt_load_addr + 
+                                            (count << PAGE_SHIFT));
+
+            /* make apropriate entry in the page directory */
+            pgt_updates->ptr = (unsigned long)vl2e;
+            pgt_updates->val = l1tab | L2_PROT;
+            pgt_updates++;
+            num_pgt_updates++;
+            vl2e++;
+        }
+
+        if ( count < pt_start )
+        {
+            pgt_updates->ptr = (unsigned long)vl1e;
+            pgt_updates->val = (page_array[count] << PAGE_SHIFT) | L1_PROT;
+            pgt_updates++;
+            num_pgt_updates++;
+            vl1e++;
+        }
+        else
+        {
+            pgt_updates->ptr = (unsigned long)vl1e;
+            pgt_updates->val = 
+                ((page_array[count] << PAGE_SHIFT) | L1_PROT) & ~_PAGE_RW;
+            pgt_updates++;
+            num_pgt_updates++;
+            vl1e++;
+        }
+
+        pgt_updates->ptr = 
+            (page_array[count] << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
+        pgt_updates->val = count;
+        pgt_updates++;
+        num_pgt_updates++;
+    }
+
+    *virt_startinfo_addr =
+        *virt_load_addr + ((alloc_index-1) << PAGE_SHIFT);
+
+    start_info = map_pfn(pm_handle, page_array[alloc_index-1]);
+    memset(start_info, 0, sizeof(*start_info));
+    start_info->pt_base     = *virt_load_addr + ((tot_pages-1) << PAGE_SHIFT);
+    start_info->mod_start   = symtab_addr;
+    start_info->mod_len     = symtab_len;
+    start_info->nr_pages    = tot_pages;
+    start_info->shared_info = shared_info_frame << PAGE_SHIFT;
+    start_info->dom_id      = dom;
+    start_info->flags       = 0;
+    strncpy(start_info->cmd_line, cmdline, MAX_CMD_LEN);
+    start_info->cmd_line[MAX_CMD_LEN-1] = '\0';
+
+    unmap_pfn(pm_handle, start_info);
+
+    /* shared_info page starts its life empty. */
+    shared_info = map_pfn(pm_handle, shared_info_frame);
+    memset(shared_info, 0, PAGE_SIZE);
+    unmap_pfn(pm_handle, shared_info);
+
+    /* Send the page update requests down to the hypervisor. */
+    if ( send_pgupdates(xc_handle, pgt_update_arr, num_pgt_updates) < 0 )
+        goto error_out;
+
+    free(page_array);
+    free(pgt_update_arr);
+    return 0;
+
+ error_out:
+    if ( pm_handle >= 0 )
+        (void)close_pfn_mapper(pm_handle);
+    if ( page_array == NULL )
+        free(page_array);
+    if ( pgt_update_arr == NULL )
+        free(pgt_update_arr);
+    return -1;
+}
+
+int xc_netbsd_build(int xc_handle,
+                   unsigned int domid,
+                   const char *image_name,
+                   const char *cmdline)
+{
+    dom0_op_t launch_op, op;
+    unsigned long load_addr;
+    long tot_pages;
+    int kernel_fd = -1;
+    gzFile kernel_gfd = NULL;
+    int rc, i;
+    full_execution_context_t *ctxt;
+    unsigned long virt_startinfo_addr;
+
+    if ( (tot_pages = get_tot_pages(xc_handle, domid)) < 0 )
+    {
+        PERROR("Could not find total pages for domain");
+        return 1;
+    }
+
+    kernel_fd = open(image_name, O_RDONLY);
+    if ( kernel_fd < 0 )
+    {
+        PERROR("Could not open kernel image");
+        return 1;
+    }
+
+    if ( (kernel_gfd = gzdopen(kernel_fd, "rb")) == NULL )
+    {
+        PERROR("Could not allocate decompression state for state file");
+        close(kernel_fd);
+        return 1;
+    }
+
+    op.cmd = DOM0_GETDOMAININFO;
+    op.u.getdomaininfo.domain = domid;
+    if ( (do_dom0_op(xc_handle, &op) < 0) || 
+         (op.u.getdomaininfo.domain != domid) )
+    {
+        PERROR("Could not get info on domain");
+        goto error_out;
+    }
+    if ( (op.u.getdomaininfo.state != DOMSTATE_STOPPED) ||
+         (op.u.getdomaininfo.ctxt.pt_base != 0) )
+    {
+        ERROR("Domain is already constructed");
+        goto error_out;
+    }
+
+    if ( setup_guestos(xc_handle, domid, kernel_gfd, tot_pages,
+                       &virt_startinfo_addr,
+                       &load_addr, &launch_op.u.builddomain, cmdline,
+                       op.u.getdomaininfo.shared_info_frame) < 0 )
+    {
+        ERROR("Error constructing guest OS");
+        goto error_out;
+    }
+
+    if ( kernel_fd >= 0 )
+        close(kernel_fd);
+    if( kernel_gfd )
+       gzclose(kernel_gfd);
+
+    ctxt = &launch_op.u.builddomain.ctxt;
+
+    ctxt->flags = 0;
+
+    /*
+     * Initial register values:
+     *  DS,ES,FS,GS = FLAT_RING1_DS
+     *       CS:EIP = FLAT_RING1_CS:start_pc
+     *       SS:ESP = FLAT_RING1_DS:start_stack
+     *          ESI = start_info
+     *  [EAX,EBX,ECX,EDX,EDI,EBP are zero]
+     *       EFLAGS = IF | 2 (bit 1 is reserved and should always be 1)
+     */
+    ctxt->i386_ctxt.ds = FLAT_RING1_DS;
+    ctxt->i386_ctxt.es = FLAT_RING1_DS;
+    ctxt->i386_ctxt.fs = FLAT_RING1_DS;
+    ctxt->i386_ctxt.gs = FLAT_RING1_DS;
+    ctxt->i386_ctxt.ss = FLAT_RING1_DS;
+    ctxt->i386_ctxt.cs = FLAT_RING1_CS;
+    ctxt->i386_ctxt.eip = load_addr;
+    ctxt->i386_ctxt.esp = virt_startinfo_addr;
+    ctxt->i386_ctxt.esi = virt_startinfo_addr;
+    ctxt->i386_ctxt.eflags = (1<<9) | (1<<2);
+
+    /* FPU is set up to default initial state. */
+    memset(ctxt->i387_ctxt, 0, sizeof(ctxt->i387_ctxt));
+
+    /* Virtual IDT is empty at start-of-day. */
+    for ( i = 0; i < 256; i++ )
+    {
+        ctxt->trap_ctxt[i].vector = i;
+        ctxt->trap_ctxt[i].cs     = FLAT_RING1_CS;
+    }
+    ctxt->fast_trap_idx = 0;
+
+    /* No LDT. */
+    ctxt->ldt_ents = 0;
+    
+    /* Use the default Xen-provided GDT. */
+    ctxt->gdt_ents = 0;
+
+    /* Ring 1 stack is the initial stack. */
+    ctxt->ring1_ss  = FLAT_RING1_DS;
+    ctxt->ring1_esp = virt_startinfo_addr;
+
+    /* No debugging. */
+    memset(ctxt->debugreg, 0, sizeof(ctxt->debugreg));
+
+    /* No callback handlers. */
+    ctxt->event_callback_cs     = FLAT_RING1_CS;
+    ctxt->event_callback_eip    = 0;
+    ctxt->failsafe_callback_cs  = FLAT_RING1_CS;
+    ctxt->failsafe_callback_eip = 0;
+
+    launch_op.u.builddomain.domain   = domid;
+    launch_op.u.builddomain.num_vifs = 1;
+
+    launch_op.cmd = DOM0_BUILDDOMAIN;
+    rc = do_dom0_op(xc_handle, &launch_op);
+    
+    return rc;
+
+ error_out:
+    if ( kernel_fd >= 0 )
+        close(kernel_fd);
+    if( kernel_gfd )
+       gzclose(kernel_gfd);
+
+    return -1;
+}
+
+#define MYSEEK_BUFSIZE 1024
+static off_t
+myseek(gzFile gfd, off_t offset, int whence)
+{
+    unsigned char tmp[MYSEEK_BUFSIZE];
+    int c;
+
+    if (offset < 0) {
+       ERROR("seek back not supported");
+       return -1;
+    }
+
+    while (offset) {
+       c = offset;
+       if (c > MYSEEK_BUFSIZE)
+           c = MYSEEK_BUFSIZE;
+       if (gzread(gfd, tmp, c) != c) {
+           PERROR("Error seeking in image.");
+           return -1;
+       }
+       offset -= c;
+    }
+
+    return 0;                  /* XXX */
+}
+
+/* 
+ * NetBSD memory layout:
+ *
+ * ---------------- *virt_load_addr = ehdr.e_entry (0xc0100000)
+ * | kernel text  |
+ * |              |
+ * ----------------
+ * | kernel data  |
+ * |              |
+ * ----------------
+ * | kernel bss   |
+ * |              |
+ * ---------------- *symtab_addr
+ * | symtab size  |   = *symtab_len
+ * ----------------
+ * | elf header   |   offsets to symbol sections mangled to be relative
+ * |              |   to headers location
+ * ----------------
+ * | sym section  |
+ * | headers      |
+ * ----------------
+ * | sym sections |
+ * |              |
+ * ---------------- *symtab_addr + *symtab_len
+ * | padding      |
+ * ---------------- ehdr.e_entry + *ksize << PAGE_SHIFT
+ */
+
+#define IS_TEXT(p)     (p.p_flags & PF_X)
+#define IS_DATA(p)     (p.p_flags & PF_W)
+#define IS_BSS(p)      (p.p_filesz < p.p_memsz)
+
+static int
+loadelfimage(gzFile kernel_gfd, int pm_handle, unsigned long *page_array,
+            unsigned long tot_pages, unsigned long *virt_load_addr,
+            unsigned long *ksize, unsigned long *symtab_addr,
+            unsigned long *symtab_len)
+{
+    Elf_Ehdr ehdr;
+    Elf_Phdr *phdr;
+    Elf_Shdr *shdr;
+    void *vaddr;
+    char page[PAGE_SIZE], *p;
+    unsigned long iva, maxva, symva;
+    int c, curpos, h, i, ret, s;
+
+    ret = -1;
+    phdr = NULL;
+    p = NULL;
+    maxva = 0;
+
+    if (gzread(kernel_gfd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr)) {
+       PERROR("Error reading kernel image ELF header.");
+       goto out;
+    }
+    curpos = sizeof(Elf_Ehdr);
+
+    if (!IS_ELF(ehdr)) {
+       PERROR("Image does not have an ELF header.");
+       goto out;
+    }
+
+    *virt_load_addr = ehdr.e_entry;
+
+    if ((*virt_load_addr & (PAGE_SIZE-1)) != 0) {
+        ERROR("We can only deal with page-aligned load addresses");
+        goto out;
+    }
+
+    if ((*virt_load_addr + (tot_pages << PAGE_SHIFT)) >
+       HYPERVISOR_VIRT_START) {
+        ERROR("Cannot map all domain memory without hitting Xen space");
+        goto out;
+    }
+
+
+    phdr = malloc(ehdr.e_phnum * sizeof(Elf_Phdr));
+    if (phdr == NULL) {
+       ERROR("Cannot allocate memory for Elf_Phdrs");
+       goto out;
+    }
+
+    if (myseek(kernel_gfd, ehdr.e_phoff - curpos, SEEK_SET) == -1) {
+       ERROR("Seek to program header failed");
+       goto out;
+    }
+    curpos = ehdr.e_phoff;
+
+    if (gzread(kernel_gfd, phdr, ehdr.e_phnum * sizeof(Elf_Phdr)) !=
+       ehdr.e_phnum * sizeof(Elf_Phdr)) {
+       PERROR("Error reading kernel image ELF program header.");
+       goto out;
+    }
+    curpos += ehdr.e_phnum * sizeof(Elf_Phdr);
+
+
+    for (h = 0; h < ehdr.e_phnum; h++) {
+       if (phdr[h].p_type != PT_LOAD ||
+           (phdr[h].p_flags & (PF_W|PF_X)) == 0)
+           continue;
+
+       if (IS_TEXT(phdr[h]) || IS_DATA(phdr[h])) {
+           if (myseek(kernel_gfd, phdr[h].p_offset - curpos, SEEK_SET) ==
+               -1) {
+               ERROR("Seek to section failed");
+               goto out;
+           }
+           curpos = phdr[h].p_offset;
+
+           for (iva = phdr[h].p_vaddr;
+                iva < phdr[h].p_vaddr + phdr[h].p_filesz; iva += c) {
+               c = PAGE_SIZE - (iva & (PAGE_SIZE - 1));
+               if (iva + c > phdr[h].p_vaddr + phdr[h].p_filesz)
+                   c = phdr[h].p_vaddr + phdr[h].p_filesz - iva;
+               if (gzread(kernel_gfd, page, c) != c) {
+                   PERROR("Error reading kernel image page.");
+                   goto out;
+               }
+               curpos += c;
+               vaddr = map_pfn(pm_handle, page_array[(iva - *virt_load_addr)
+                                                     >> PAGE_SHIFT]);
+               if (vaddr == NULL) {
+                   ERROR("Couldn't map guest memory");
+                   goto out;
+               }
+               DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)iva,
+                        vaddr + (iva & (PAGE_SIZE - 1)), c));
+               memcpy(vaddr + (iva & (PAGE_SIZE - 1)), page, c);
+               unmap_pfn(pm_handle, vaddr);
+           }
+
+           if (phdr[h].p_vaddr + phdr[h].p_filesz > maxva)
+               maxva = phdr[h].p_vaddr + phdr[h].p_filesz;
+       }
+
+       if (IS_BSS(phdr[h])) {
+           /* XXX maybe clear phdr[h].p_memsz bytes from
+              phdr[h].p_vaddr + phdr[h].p_filesz ??? */
+           if (phdr[h].p_vaddr + phdr[h].p_memsz > maxva)
+               maxva = phdr[h].p_vaddr + phdr[h].p_memsz;
+           DPRINTF(("bss from %p to %p, maxva %p\n",
+                    (void *)(phdr[h].p_vaddr + phdr[h].p_filesz),
+                    (void *)(phdr[h].p_vaddr + phdr[h].p_memsz),
+                    (void *)maxva));
+       }
+    }
+
+    p = malloc(sizeof(int) + sizeof(Elf_Ehdr) +
+              ehdr.e_shnum * sizeof(Elf_Shdr));
+    if (p == NULL) {
+       ERROR("Cannot allocate memory for Elf_Shdrs");
+       goto out;
+    }
+
+    shdr = (Elf_Shdr *)(p + sizeof(int) + sizeof(Elf_Ehdr));
+
+    if (myseek(kernel_gfd, ehdr.e_shoff - curpos, SEEK_SET) == -1) {
+       ERROR("Seek to symbol header failed");
+       goto out;
+    }
+    curpos = ehdr.e_shoff;
+
+    if (gzread(kernel_gfd, shdr, ehdr.e_shnum * sizeof(Elf_Shdr)) !=
+       ehdr.e_shnum * sizeof(Elf_Shdr)) {
+       PERROR("Error reading kernel image ELF symbol header.");
+       goto out;
+    }
+    curpos += ehdr.e_shnum * sizeof(Elf_Shdr);
+
+    maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+    symva = maxva;
+    maxva += sizeof(int);
+    *symtab_addr = maxva;
+    *symtab_len = 0;
+    maxva += sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr);
+    maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+    for (h = 0; h < ehdr.e_shnum; h++) {
+       if (shdr[h].sh_type == SHT_STRTAB) {
+           for (i = 0; i < ehdr.e_shnum; i++)
+               if (shdr[i].sh_type == SHT_SYMTAB &&
+                   shdr[i].sh_link == h)
+                   break;
+           if (i == ehdr.e_shnum) {
+               shdr[h].sh_offset = 0;
+               continue;
+           }
+       }
+
+       if (shdr[h].sh_type == SHT_STRTAB ||
+           shdr[h].sh_type == SHT_SYMTAB) {
+           if (myseek(kernel_gfd, shdr[h].sh_offset - curpos, SEEK_SET) ==
+               -1) {
+               ERROR("Seek to symbol section failed");
+               goto out;
+           }
+           curpos = shdr[h].sh_offset;
+
+           shdr[h].sh_offset = maxva - *symtab_addr;
+
+           DPRINTF(("copy section %d, size 0x%x\n", h, shdr[h].sh_size));
+           for (i = 0; i < shdr[h].sh_size; i += c, maxva += c) {
+               c = PAGE_SIZE - (maxva & (PAGE_SIZE - 1));
+               if (c > (shdr[h].sh_size - i))
+                   c = shdr[h].sh_size - i;
+               if (gzread(kernel_gfd, page, c) != c) {
+                   PERROR("Error reading kernel image page.");
+                   goto out;
+               }
+               curpos += c;
+
+               vaddr = map_pfn(pm_handle, page_array[(maxva - *virt_load_addr)
+                                                     >> PAGE_SHIFT]);
+               if (vaddr == NULL) {
+                   ERROR("Couldn't map guest memory");
+                   goto out;
+               }
+               DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)maxva,
+                        vaddr + (maxva & (PAGE_SIZE - 1)), c));
+               memcpy(vaddr + (maxva & (PAGE_SIZE - 1)), page, c);
+               unmap_pfn(pm_handle, vaddr);
+           }
+
+           *symtab_len += shdr[h].sh_size;
+           maxva = (maxva + ELFROUND - 1) & ~(ELFROUND - 1);
+
+       }
+       shdr[h].sh_name = 0;
+    }
+
+    if (*symtab_len == 0) {
+       DPRINTF(("no symbol table\n"));
+       *symtab_addr = 0;
+       ret = 0;
+       goto out;
+    }
+
+    DPRINTF(("sym header va %p from %p/%p size %x/%x\n", (void *)symva,
+            shdr, p, ehdr.e_shnum * sizeof(Elf_Shdr),
+            ehdr.e_shnum * sizeof(Elf_Shdr) + sizeof(Elf_Ehdr)));
+    ehdr.e_phoff = 0;
+    ehdr.e_shoff = sizeof(Elf_Ehdr);
+    ehdr.e_phentsize = 0;
+    ehdr.e_phnum = 0;
+    ehdr.e_shstrndx = SHN_UNDEF;
+    memcpy(p + sizeof(int), &ehdr, sizeof(Elf_Ehdr));
+    *(int *)p = maxva - *symtab_addr;
+
+    s = sizeof(int) + sizeof(Elf_Ehdr) + ehdr.e_shnum * sizeof(Elf_Shdr);
+    for (i = 0; i < s; i += c, symva += c) {
+       c = PAGE_SIZE - (symva & (PAGE_SIZE - 1));
+       if (c > s - i)
+           c = s - i;
+       vaddr = map_pfn(pm_handle, page_array[(symva - *virt_load_addr)
+                                             >> PAGE_SHIFT]);
+       if (vaddr == NULL) {
+           ERROR("Couldn't map guest memory");
+           goto out;
+       }
+       DPRINTF(("copy page %p to %p, count 0x%x\n", (void *)symva,
+                vaddr + (symva & (PAGE_SIZE - 1)), c));
+       memcpy(vaddr + (symva & (PAGE_SIZE - 1)), p + i,
+              c);
+       unmap_pfn(pm_handle, vaddr);
+    }
+
+    *symtab_len = maxva - *symtab_addr;
+
+    ret = 0;
+
+  out:
+    if (ret == 0) {
+       maxva = (maxva + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
+       *ksize = (maxva - *virt_load_addr) >> PAGE_SHIFT;
+
+       DPRINTF(("virt_addr %p, kpages 0x%lx, symtab_addr %p, symtab_len %p\n",
+                (void *)*virt_load_addr, *ksize, (void *)*symtab_addr,
+                (void *)*symtab_len));
+    }
+
+    if (phdr)
+       free(phdr);
+    if (p)
+       free(p);
+    return ret;
+}
index ee91ca71953b2138075d479cb51f1ba7a64d1f9f..d1052efd938c743e1452d4cb683dd7c1fd6aa7dc 100644 (file)
@@ -221,6 +221,27 @@ static PyObject *pyxc_linux_build(PyObject *self,
     return PyInt_FromLong(ret);
 }
 
+static PyObject *pyxc_netbsd_build(PyObject *self,
+                                   PyObject *args,
+                                   PyObject *kwds)
+{
+    XcObject *xc = (XcObject *)self;
+
+    unsigned int dom;
+    char        *image, *ramdisk = NULL, *cmdline = "";
+    int          ret;
+
+    static char *kwd_list[] = { "dom", "image", "ramdisk", "cmdline", NULL };
+
+    if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is|ss", kwd_list, 
+                                      &dom, &image, &ramdisk, &cmdline) )
+        return NULL;
+
+    ret = xc_netbsd_build(xc->xc_handle, dom, image, cmdline);
+    
+    return PyInt_FromLong(ret);
+}
+
 static PyObject *pyxc_bvtsched_global_set(PyObject *self,
                                           PyObject *args,
                                           PyObject *kwds)
@@ -687,6 +708,15 @@ static PyMethodDef pyxc_methods[] = {
       " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
       "Returns: [int] new domain identifier on success; -1 on error.\n" },
 
+    { "netbsd_build", 
+      (PyCFunction)pyxc_netbsd_build, 
+      METH_VARARGS | METH_KEYWORDS, "\n"
+      "Build a new NetBSD guest OS.\n"
+      " dom     [int]:      Identifier of domain to build into.\n"
+      " image   [str]:      Name of kernel image file. May be gzipped.\n"
+      " cmdline [str, n/a]: Kernel parameters, if any.\n\n"
+      "Returns: [int] new domain identifier on success; -1 on error.\n" },
+
     { "bvtsched_global_set", 
       (PyCFunction)pyxc_bvtsched_global_set, 
       METH_VARARGS | METH_KEYWORDS, "\n"